I have a React UI. I need to implement Okta Web app, with server-side authentication. The server I am using is Python. Unable to fix the issue with Okta giving this error: 'AuthSdkError: Unable to retrieve OAuth redirect params from storage'
From looking at my debugging logs, cookie data all seems valid and present.
Python:
@app.route("/login")
def login():
session['app_state'] = secrets.token_urlsafe(64)
session['code_verifier'] = secrets.token_urlsafe(64)
# Debugging: Print session data
print("Session before redirect:", dict(session))
hashed = hashlib.sha256(session['code_verifier'].encode('ascii')).digest()
encoded = base64.urlsafe_b64encode(hashed)
code_challenge = encoded.decode('ascii').strip('=')
query_params = {
'client_id': os.environ['CLIENT_ID'],
'redirect_uri': "http://localhost:5000/login/callback",
'scope': "openid email profile",
'state': session['app_state'],
'code_challenge': code_challenge,
'code_challenge_method': 'S256',
'response_type': 'code',
'response_mode': 'query'
}
request_uri = "{base_url}?{query_params}".format(
base_url=os.environ['ORG_URL'] + "oauth2/default/v1/authorize",
query_params=requests.compat.urlencode(query_params)
)
print("Redirecting to: ", request_uri)
return redirect(request_uri)
@app.route("/login/callback")
def callback():
print("Session in callback before checking state:", dict(session))
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
code = request.args.get("code")
app_state = request.args.get("state")
# Debugging: Print session data and received state
print("Callback session data: ", dict(session))
print(f"Received state: {app_state}")
print(f"Expected state: {session.get('app_state')}")
print(f"Received code: {code}")
if app_state != session.get('app_state'):
print(f"App state mismatch: expected {session.get('app_state')} but got {app_state}")
return "The app state does not match", 400
if not code:
return "The code was not returned or is not accessible", 403
query_params = {
'grant_type': 'authorization_code',
'code': code,
'redirect_uri': request.base_url,
'code_verifier': session['code_verifier']
}
query_params = requests.compat.urlencode(query_params)
exchange = requests.post(
os.environ['ORG_URL'] + "oauth2/default/v1/token",
headers=headers,
data=query_params,
auth=(os.environ['CLIENT_ID'], os.environ['CLIENT_SECRET']),
).json()
# Debugging: Print token exchange response
print("Token exchange response: ", exchange)
if not exchange.get("token_type"):
return "Unsupported token type. Should be 'Bearer'.", 403
access_token = exchange["access_token"]
id_token = exchange["id_token"]
userinfo_response = requests.get(os.environ['ORG_URL'] + "oauth2/default/v1/userinfo",
headers={'Authorization': f'Bearer {access_token}'}).json()
unique_id = userinfo_response["sub"]
user_email = userinfo_response["email"]
user_name = userinfo_response["given_name"]
user = User(
id_=unique_id, name=user_name, email=user_email
)
if not User.get(unique_id):
User.create(unique_id, user_name, user_email)
login_user(user)
# Clean up session
session.pop('app_state', None)
session.pop('code_verifier', None)
return send_from_directory(app.static_folder, 'index.html')
React app.js
const oktaAuth = new OktaAuth({
issuer: 'https://dev-xxxxxxxxx.okta.com/oauth2/default',
clientId: 'xxxxxxxxxxxxxx',
redirectUri: window.location.origin + '/login/callback'
});
const App = () => {
const history = useHistory();
const restoreOriginalUri = async (_oktaAuth, originalUri) => {
history.replace(toRelativeUrl(originalUri || '/', window.location.origin));
};
return (
<Security oktaAuth={oktaAuth} restoreOriginalUri={restoreOriginalUri}>
<Switch>
<Route path="/" exact component={Home} />
<Route path="/login/callback" component={LoginCallback} />
</Switch>
</Security>
);
};
const RouterApp = () => (
<Router>
<App />
</Router>
);
export default RouterApp;