(20250104) Breeze authorization will be accepted now.
This commit is contained in:
@@ -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
|
||||
|
||||
# ┏┳┓ ┓• ┏┓ ┓ ┓
|
||||
# ┃ ┏┓┏┓┏┫┓┏┓┏┓ ┗┓┓┏┏┳┓┣┓┏┓┃┏
|
||||
|
||||
Reference in New Issue
Block a user