(20250104) Breeze authorization will be accepted now.

This commit is contained in:
2025-01-04 15:22:51 +05:30
parent aadcc87e2a
commit 0c2d7816f4
13 changed files with 316 additions and 83 deletions
@@ -52,6 +52,7 @@ from models.api.finstitutions.trading.symbols.list import (
TradingSymbolListBrokerResponse,
TradingSymbol
)
from models.finstitutions.trading.oauth import TradingOAuthCallbackResponse
# To work with MongoDB:
from bson.objectid import ObjectId
@@ -179,50 +180,79 @@ class ZerodhaKiteTradingController(TradingController):
self,
sql_conn: AsyncMySQL,
mongo_data_conn: AsyncMongo,
inbound_data: dict
) -> bool:
inbound_data: dict,
client_user_id: str
) -> TradingOAuthCallbackResponse:
"""
When the end user interacts with Zerodha's APIs, Zerodha's servers issue a callback like this:
http://127.0.0.1:5999/auth/callback?action=login&type=login&status=success&request_token=the-request-token
We must use the request token to get the access token. The access token is the thing that we must hold onto for
executing actual actions like subscribing to live market feed, placing trades, etc.
NOTE: Please ensure that you set the 'Redirect URL' such that is passes back Kite's 'api_key' back through the
callback URL. This can be one by setting the value manually as a query param on the app's configuration
page. E.g.: http://127.0.0.1:5999/auth/callback?api_key=user_api_key
NOTE: Please ensure that you set the 'Redirect URL' in the format as shown below:
01. http://127.0.0.1:5106/converse/finstitutions/trading/oauth/callback/zerodhaKite/<client_user_id>
02. https://api.thecaoffice.com/converse/finstitutions/trading/oauth/callback/zerodhaKite/<client_user_id>
BACKWARD COMPATIBILITY:
Earlier, we used to set the same API key in the callback URL as a query param like shown below:
E.g.: http://127.0.0.1:5106/converse/finstitutions/trading/oauth/callback/zerodhaKite?api_key=user_api_key
:param sql_conn: The database connection to use to perform this activity.
:param mongo_data_conn: The database connection to use to perform this activity.
:param inbound_data: The data that came in from the broker. This could be in the JSON body, query params, etc.
:return: True if the callback loop was completed successfully, else False..
:param client_user_id: How the trading client identifies this user.
:return: A structured response to capture the process of callback handling.
"""
# Start by assuming failure:
success = False
response = TradingOAuthCallbackResponse()
zerodha_auth_token = None
# Check if either the new system or the old system is being followed.
# At least one is needed:
api_key = inbound_data.get("api_key")
if not api_key and not client_user_id:
response.message = "Your callback URL hasn't been configured properly."
return response
# Get the token from the database:
old_condition = mongo_data_conn.dict_to_dot_notation({"auth": {"apiKey": api_key}})
condition = mongo_data_conn.dict_to_dot_notation({"auth": {"userId": client_user_id}})
auth_token = await self.get_token_from_filter(
mongo_data_conn = mongo_data_conn,
filter_json = mongo_data_conn.dict_to_dot_notation({
"auth": {
"apiKey": inbound_data.get(
"api_key",
"Hint: Put the user's app's key in the query params of the 'Redirect URL'"
)
}
})
filter_json = {"$or": [old_condition, condition]}
)
# If not such auth token exists:
if not auth_token: return success
if not auth_token:
response.message = (
f"No such integration found in our system. "
"Please add this integration first and then try again."
)
return response
# Get the final access tokens set from Zerodha Kite:
kite = KiteConnect(api_key = auth_token.auth["apiKey"])
session_data = kite.generate_session(
request_token = inbound_data["request_token"],
api_secret = auth_token.auth["apiSecret"]
)
zerodha_auth_token = ZerodhaKiteAuthTokens(**session_data)
try:
kite = KiteConnect(api_key = auth_token.auth["apiKey"])
session_data = kite.generate_session(
request_token = inbound_data["request_token"],
api_secret = auth_token.auth["apiSecret"]
)
zerodha_auth_token = ZerodhaKiteAuthTokens(**session_data)
except Exception as exception:
response.exception = exception
response.message = str(exception)
return response
# Ensure that the client user id of the incoming callback and the one given in Zerodha's session data match:
if (
client_user_id is not None and # ................ For backward compatibility.
zerodha_auth_token.userId != client_user_id # ... New mechanism that verifies account match.
):
response.message = (
f"We were expecting authorization for the account '{client_user_id}', "
f"but Zerodha says the authorization was granted for the account '{zerodha_auth_token.userId}'. "
"This could be because of a misconfigured callback URL."
)
return response
# Prepare the inputs to save to the database:
auth_url = await self.get_authorization_url(api_key = auth_token.auth["apiKey"])
@@ -242,8 +272,15 @@ class ZerodhaKiteTradingController(TradingController):
display_picture = zerodha_auth_token.displayPictureUrl
)
# If saving the token fails:
if not success:
response.message = "Something went wrong towards the end of the authorization cycle."
return response
# Done here:
return success
response.success = True
response.message = "Authorization cycle successfully completed."
return response
# ┏┳┓ ┓• ┏┓ ┓ ┓
# ┃ ┏┓┏┓┏┫┓┏┓┏┓ ┗┓┓┏┏┳┓┣┓┏┓┃┏