Skip to content

Commit 7ffd1de

Browse files
committed
feat: enhance OAuth handling with improved error logging and state management
1 parent 2fd3694 commit 7ffd1de

File tree

2 files changed

+35
-25
lines changed

2 files changed

+35
-25
lines changed

packages/nextjs/src/client/contexts/Asgardeo/AsgardeoProvider.tsx

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -119,10 +119,22 @@ const AsgardeoClientProvider: FC<PropsWithChildren<AsgardeoClientProviderProps>>
119119

120120
// Handle OAuth callback automatically
121121
useEffect(() => {
122+
// React 18.x Strict.Mode has a new check for `Ensuring reusable state` to facilitate an upcoming react feature.
123+
// https://reactjs.org/docs/strict-mode.html#ensuring-reusable-state
124+
// This will remount all the useEffects to ensure that there are no unexpected side effects.
125+
// When react remounts the signIn hook of the AuthProvider, it will cause a race condition. Hence, we have to
126+
// prevent the re-render of this hook as suggested in the following discussion.
127+
// https://github.com/reactwg/react-18/discussions/18#discussioncomment-795623
128+
if (reRenderCheckRef.current) {
129+
return;
130+
}
131+
132+
reRenderCheckRef.current = true;
133+
122134
// Don't handle callback if already signed in
123135
if (isSignedIn) return;
124136

125-
const processOAuthCallback = async () => {
137+
(async () => {
126138
try {
127139
const code = searchParams.get('code');
128140
const state = searchParams.get('state');
@@ -132,13 +144,8 @@ const AsgardeoClientProvider: FC<PropsWithChildren<AsgardeoClientProviderProps>>
132144

133145
// Check for OAuth errors first
134146
if (error) {
135-
console.error('[AsgardeoClientProvider] OAuth error:', error, errorDescription);
136-
// Redirect to sign-in page with error
137-
router.push(
138-
`/signin?error=${encodeURIComponent(error)}&error_description=${encodeURIComponent(
139-
errorDescription || '',
140-
)}`,
141-
);
147+
logger.error('[AsgardeoClientProvider] An error was received for the initiated sign-in request.');
148+
142149
return;
143150
}
144151

@@ -157,21 +164,16 @@ const AsgardeoClientProvider: FC<PropsWithChildren<AsgardeoClientProviderProps>>
157164
window.location.reload();
158165
}
159166
} else {
160-
router.push(
161-
`/signin?error=authentication_failed&error_description=${encodeURIComponent(
162-
result.error || 'Authentication failed',
163-
)}`,
167+
logger.error(
168+
`[AsgardeoClientProvider] An error occurred while signing in: ${result.error || 'Authentication failed'}`,
164169
);
165170
}
166171
}
167172
} catch (error) {
168-
console.error('[AsgardeoClientProvider] Failed to handle OAuth callback:', error);
169-
router.push('/signin?error=authentication_failed');
173+
logger.error('[AsgardeoClientProvider] Failed to handle OAuth callback:', error);
170174
}
171-
};
172-
173-
processOAuthCallback();
174-
}, [searchParams, router, isSignedIn, handleOAuthCallback]);
175+
})();
176+
}, []);
175177

176178
useEffect(() => {
177179
if (!preferences?.theme?.mode || preferences.theme.mode === 'system') {

packages/nextjs/src/server/actions/handleOAuthCallbackAction.ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import {cookies} from 'next/headers';
2222
import AsgardeoNextClient from '../../AsgardeoNextClient';
2323
import SessionManager from '../../utils/SessionManager';
24+
import logger from '../../utils/logger';
2425

2526
/**
2627
* Server action to handle OAuth callback with authorization code.
@@ -68,11 +69,15 @@ const handleOAuthCallbackAction = async (
6869
const tempSession = await SessionManager.verifyTempSession(tempSessionToken);
6970
sessionId = tempSession.sessionId;
7071
} catch {
71-
// TODO: Invalid temp session, throw error.
72+
logger.error(
73+
'[handleOAuthCallbackAction] Invalid temporary session token, falling back to session ID from cookies.',
74+
);
7275
}
7376
}
7477

7578
if (!sessionId) {
79+
logger.error('[handleOAuthCallbackAction] No session ID found in cookies or temporary session token.');
80+
7681
return {
7782
success: false,
7883
error: 'No session found. Please start the authentication flow again.',
@@ -92,10 +97,13 @@ const handleOAuthCallbackAction = async (
9297

9398
if (signInResult) {
9499
try {
95-
const idToken = await asgardeoClient.getDecodedIdToken(sessionId);
96-
const accessToken: string = signInResult['access_token'];
100+
const idToken = await asgardeoClient.getDecodedIdToken(
101+
sessionId,
102+
signInResult['id_token'] || signInResult['idToken'],
103+
);
104+
const accessToken: string = signInResult['accessToken'] || signInResult['access_token'];
97105
const userIdFromToken = idToken.sub || signInResult['sub'] || sessionId;
98-
const scopes = idToken['scope'] ? idToken['scope'].split(' ') : [];
106+
const scopes = signInResult['scope'];
99107
const organizationId = idToken['user_org'] || idToken['organization_id'];
100108

101109
const sessionToken = await SessionManager.createSessionToken(
@@ -110,9 +118,9 @@ const handleOAuthCallbackAction = async (
110118

111119
cookieStore.delete(SessionManager.getTempSessionCookieName());
112120
} catch (error) {
113-
console.warn(
114-
'[handleOAuthCallbackAction] Failed to create JWT session, continuing with legacy session:',
115-
error,
121+
logger.error(
122+
`[handleOAuthCallbackAction] Failed to create JWT session, continuing with legacy session:
123+
${typeof error === 'string' ? error : JSON.stringify(error)}`,
116124
);
117125
}
118126
}

0 commit comments

Comments
 (0)