diff --git a/src/grant_base.ts b/src/grant_base.ts index 5c4fb74..51dd847 100644 --- a/src/grant_base.ts +++ b/src/grant_base.ts @@ -7,6 +7,7 @@ interface AccessTokenResponse { "token_type": string; "expires_in"?: number; "refresh_token"?: string; + "id_token"?: string; scope?: string; } @@ -111,6 +112,15 @@ export abstract class OAuth2GrantBase { response, ); } + if ( + body.id_token !== undefined && + typeof body.id_token !== "string" + ) { + throw new TokenResponseError( + "id_token is not a string", + response, + ); + } if ( body.expires_in !== undefined && typeof body.expires_in !== "number" ) { @@ -134,6 +144,9 @@ export abstract class OAuth2GrantBase { if (body.refresh_token) { tokens.refreshToken = body.refresh_token; } + if (body.id_token) { + tokens.idToken = body.id_token; + } if (body.expires_in) { tokens.expiresIn = body.expires_in; } diff --git a/src/resource_owner_password_credentials_test.ts b/src/resource_owner_password_credentials_test.ts index 9c1d478..3f8e623 100644 --- a/src/resource_owner_password_credentials_test.ts +++ b/src/resource_owner_password_credentials_test.ts @@ -154,6 +154,25 @@ Deno.test("ResourceOwnerPasswordCredentialsGrant.getToken throws if the server r ); }); +Deno.test("ResourceOwnerPasswordCredentialsGrant.getToken throws if the server response's id_token property is present but not a string", async () => { + await assertRejects( + () => + mockATResponse( + () => + getOAuth2Client().ropc.getToken({ username: "un", password: "pw" }), + { + body: { + access_token: "at", + token_type: "tt", + id_token: 123 as any, + }, + }, + ), + TokenResponseError, + "Invalid token response: id_token is not a string", + ); +}); + Deno.test("ResourceOwnerPasswordCredentialsGrant.getToken throws if the server response's expires_in property is present but not a number", async () => { await assertRejects( () => diff --git a/src/test_utils.ts b/src/test_utils.ts index 0a96205..dd2f8b4 100644 --- a/src/test_utils.ts +++ b/src/test_utils.ts @@ -42,6 +42,7 @@ interface AccessTokenResponse { "token_type": string; "expires_in"?: number; "refresh_token"?: string; + "id_token"?: string; scope?: string; } diff --git a/src/types.ts b/src/types.ts index dcc3c18..60d0b73 100644 --- a/src/types.ts +++ b/src/types.ts @@ -39,6 +39,10 @@ export interface Tokens { * which circumstances you'll receive one. */ refreshToken?: string; + /** + * The optional ID token returned by the authorization server. + */ + idToken?: string; /** * The scopes that were granted by the user. *