Skip to content

Commit df3c1f3

Browse files
committed
feat(auth): be more generous with accepting non-standard responses from the idp
1 parent 4a5e6ae commit df3c1f3

2 files changed

Lines changed: 20 additions & 12 deletions

File tree

packages/auth/README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ ___
269269

270270
### idToken
271271

272-
**idToken**: `string`
272+
`Optional` **idToken**: `string`
273273

274274
OAuth ID token provided by the IDP
275275

@@ -286,6 +286,12 @@ OAuth refresh token provided by the IDP
286286

287287
Object representing the user details as provided by the IdP `userInfo` endpoint.
288288

289+
## Hierarchy
290+
291+
- `Record`<`string`, `unknown`\>
292+
293+
**`UserInfo`**
294+
289295
## Properties
290296

291297
### email

packages/auth/src/index.tsx

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import React, {
1010
import { useQuery, useWindowFocus, useCachedQuery, querystring } from '@emdgroup/react-query';
1111
import { useLocalStorage, useSessionStorage } from '@emdgroup/react-storage';
1212

13-
async function generateVerifier(size = 16): Promise<Uint8Array> {
13+
async function generateVerifier(size = 32): Promise<Uint8Array> {
1414
const randomBytes = new Uint8Array(size);
1515
return crypto.getRandomValues(randomBytes);
1616
}
@@ -37,7 +37,7 @@ export interface UserSession {
3737
/** OAuth refresh token provided by the IDP */
3838
refreshToken?: string;
3939
/** OAuth ID token provided by the IDP */
40-
idToken: string;
40+
idToken?: string;
4141
/** Epoch time in seconds when the access token expires */
4242
expires: number;
4343
}
@@ -49,16 +49,16 @@ function isObject(args: unknown): args is Record<string, unknown> {
4949
function isSession(args: unknown): args is UserSession {
5050
return isObject(args) &&
5151
typeof args.accessToken === 'string' &&
52-
(typeof args.refreshToken === 'string' || args.refreshToken === undefined) &&
53-
typeof args.idToken === 'string' &&
52+
isStringOrUndefined(args.refreshToken) &&
53+
isStringOrUndefined(args.idToken) &&
5454
typeof args.expires === 'number';
5555
}
5656

5757
interface TokenResponse {
5858
access_token: string;
5959
refresh_token: string;
6060
id_token: string;
61-
token_type: 'Bearer';
61+
token_type: string;
6262
expires_in: number;
6363
}
6464

@@ -71,13 +71,16 @@ interface IdpErrorResponse {
7171
error_description: string;
7272
}
7373

74+
function isStringOrUndefined(arg: unknown): arg is string | undefined | null {
75+
return typeof arg === 'string' || arg === undefined || arg === null;
76+
}
77+
7478
function isTokenResponse(args: unknown): args is TokenResponse {
7579
return isObject(args) &&
7680
typeof args.access_token === 'string' &&
77-
typeof args.refresh_token === 'string' &&
78-
typeof args.id_token === 'string' &&
81+
isStringOrUndefined(args.refresh_token) &&
82+
isStringOrUndefined(args.id_token) &&
7983
typeof args.token_type === 'string' &&
80-
args.token_type === 'Bearer' &&
8184
typeof args.expires_in === 'number';
8285
}
8386

@@ -113,7 +116,7 @@ export interface LoginOptions {
113116
* Object representing the user details as provided by the IdP `userInfo` endpoint.
114117
*/
115118

116-
export interface UserInfo {
119+
export interface UserInfo extends Record<string, unknown> {
117120
/** Email address */
118121
email: string;
119122
/** Given name of provided */
@@ -351,10 +354,9 @@ export function UserContextProvider({
351354
useEffect(() => {
352355
if (!userInfo && (userInfoStatus === 'success')) {
353356
setUserInfo({
354-
email: userInfoResponse.email,
355357
familyName: userInfoResponse.family_name,
356358
givenName: userInfoResponse.given_name,
357-
sub: userInfoResponse.sub,
359+
...userInfoResponse,
358360
});
359361
} else if (userInfoStatus === 'error') setRefreshSession(true);
360362
}, [userInfo, userInfoStatus, setUserInfo, userInfoResponse, clearSession]);

0 commit comments

Comments
 (0)