angular-auth-oidc-client icon indicating copy to clipboard operation
angular-auth-oidc-client copied to clipboard

[Bug]: Authorization header stops being set if `id_token` is missing in the refresh token response

Open ccphelps opened this issue 2 years ago • 1 comments

What Version of the library are you using?

13.0.0

Describe the bug

When the refresh token process is executed, the authnResult object is overwritten with the response. NetIQ does not return an id_token from from the refresh process. After the refresh, the application receives errors saying isAuthenticated is false. Additional HTTP calls error because the Authorization header is not set.

The user is logged in, but the id_token is required for a user to be identified as logged in. When id_token is null or undefined, isAuthenticated calls fail: https://github.com/damienbod/angular-auth-oidc-client/blob/main/projects/angular-auth-oidc-client/src/lib/auth-state/auth-state.service.ts#L157

This causes the check in the AuthInterceptor to fail to fetch the access_token properly (isAuthenticated returns false): https://github.com/damienbod/angular-auth-oidc-client/blob/main/projects/angular-auth-oidc-client/src/lib/interceptor/auth.interceptor.ts#L46-L52

Let me know if you need any other information from us on this 👍

To Reproduce

Steps to reproduce the behavior:

  1. Using identify provider NetIQ (Or an identify provider that does not return an id_token on token refresh)

Expected behavior

User access_token should be refreshed and future https calls identified in secureRoutes should have the authorization header

Screenshots

If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

  • OS: Mac OS 12.3.1
  • Browser Chrome
  • Version 100.0.4896.127

Smartphone (please complete the following information):

  • Device: [e.g. iPhone6]
  • OS: [e.g. iOS8.1]
  • Browser [e.g. stock browser, safari]
  • Version [e.g. 22]

Additional context

Configuration:

{
    `logLevel`: LogLevel.Debug,
    `authority`: authConfig.authority,
    `redirectUrl`: authConfig.redirectUri,
    `postLogoutRedirectUri`: window.location.origin,
    `clientId`: authConfig.clientId,
    'scope': 'openid profile usermanager roles',
    'responseType': 'code',
    'silentRenew': true,
    'useRefreshToken': true,
    'autoUserInfo': true,
    'enableIdTokenExpiredValidationInRenew': false,
    'allowUnsafeReuseRefreshToken': true,
    'renewTimeBeforeTokenExpiresInSeconds': 3595, // our tokens expire in an hour, this is for testing
    'customParamsRefreshTokenRequest': {
        scope: 'openid profile usermanager roles',
    },
    'unauthorizedRoute': '/unauthorized',
    'forbiddenRoute': '/forbidden',
    'secureRoutes': ['/'],
};

authorization_code Request

grant_type: authorization_code
client_id: *redacted client_id*
code_verifier: 64b7f02d161445f1b7c447dbcfa8f252251bda6c7a2dc51faeee043679c3LYCbh8R
code: ...
redirect_uri: *redacted*

authorization_code Response

{
	"access_token":"eyJ...",
	"token_type":"bearer",
	"expires_in":3599,
	"refresh_token":"eyJ...",
	"id_token":"eyJ...",
	"scope":"profile roles"
}

refresh_token Request

grant_type: refresh_token
client_id: *redacted client_id*
refresh_token: eyJ...
scope: openid profile usermanager roles

refresh_token Response

{
	"access_token":"eyJ...",
	"token_type":"bearer",
	"expires_in":3599,
	"scope":"profile roles"
}
Debug output
    core.mjs:24863 Angular is running in development mode. Call enableProdMode() to enable production mode.
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - Working with config '0-*redacted client_id*' using https://*redacted*.com/nidp/oauth/nam
    angular-auth-oidc-client.mjs:157 [DEBUG] 0-*redacted client_id* - currentUrl to check auth with:  https://localhost:4200/authcallback?code=/...
    angular-auth-oidc-client.mjs:157 [DEBUG] 0-*redacted client_id* - running validation for callback https://localhost:4200/authcallback?code=/...
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - Did not find any configured route for route https://*redacted*.com/nidp/oauth/nam/token
    index.js:551 [webpack-dev-server] Live Reloading enabled.
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - AuthResult '{
      "access_token": "eyJ...",
      "token_type": "bearer",
      "expires_in": 3599,
      "refresh_token": "eyJ...",
      "id_token": "eyJ...",
      "scope": "profile roles",
      "state": "cb685b592a6575ee0c997d3f85c123b42bymgtAYr",
      "session_state": ""
    }'.
          AuthCallback created, begin token validation
    angular-auth-oidc-client.mjs:157 [DEBUG] 0-*redacted client_id* - Getting signinkeys from  https://*redacted*.com/nidp/oauth/nam/keys
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - Did not find any configured route for route https://*redacted*.com/nidp/oauth/nam/keys
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - validate id token iat max offset 0 < 120000
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - Has idToken expired: false --> expires in 60:00 , 12:18:19 PM > 11:18:19 AM
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - Code Flow active, and no at_hash in the id_token, skipping check!
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - authCallback token(s) validated, continue
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - storing the accessToken 'eyJ...'
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - '/api/contact' matches configured route '/'
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - '/api/contact' matches configured route '/', adding token
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - '/api/navigation/oneplatform' matches configured route '/'
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - '/api/navigation/oneplatform' matches configured route '/', adding token
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - Did not find any configured route for route https://*redacted*.com/nidp/oauth/nam/userinfo
    angular-auth-oidc-client.mjs:157 [DEBUG] 0-*redacted client_id* - Received user data:  {preferredTimeZone: 'Etc/GMT+12', sub: '3c0dd97642498c468e793c0dd9764249', mail: '*@gmail.com', preferredCurrency: 'AUD', Roles: Array(7), …}
    angular-auth-oidc-client.mjs:157 [DEBUG] 0-*redacted client_id* - accessToken:  eyJ...
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - Working with config '0-*redacted client_id*' using https://*redacted*.com/nidp/oauth/nam
    angular-auth-oidc-client.mjs:157 [DEBUG] 0-*redacted client_id* - currentUrl to check auth with:  https://localhost:4200/authcallback
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - Has accessToken expired: false --> expires in 0:04 , 12:18:18 PM > 12:18:14 PM
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - persisted idToken and accessToken are valid
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - '/api/contact' matches configured route '/'
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - '/api/contact' matches configured route '/', adding token
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - '/api/navigation/oneplatform' matches configured route '/'
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - '/api/navigation/oneplatform' matches configured route '/', adding token
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - checkAuth completed - firing events now. isAuthenticated: true
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - Working with config '0-*redacted client_id*' using https://*redacted*.com/nidp/oauth/nam
    angular-auth-oidc-client.mjs:157 [DEBUG] 0-*redacted client_id* - currentUrl to check auth with:  https://localhost:4200/authcallback
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - Has accessToken expired: false --> expires in 0:04 , 12:18:18 PM > 12:18:14 PM
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - persisted idToken and accessToken are valid
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - '/api/contact' matches configured route '/'
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - '/api/contact' matches configured route '/', adding token
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - '/api/navigation/oneplatform' matches configured route '/'
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - '/api/navigation/oneplatform' matches configured route '/', adding token
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - checkAuth completed - firing events now. isAuthenticated: true
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - '/api/contact/administrators' matches configured route '/'
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - '/api/contact/administrators' matches configured route '/', adding token
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - '/api/contact/administrators' matches configured route '/'
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - '/api/contact/administrators' matches configured route '/', adding token
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - '/api/contact/administrators' matches configured route '/'
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - '/api/contact/administrators' matches configured route '/', adding token
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - Checking: silentRenewRunning: false - has idToken: true - has userData: true
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - Has accessToken expired: true --> expires in 0:00 , 12:18:18 PM > 12:18:18 PM
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - starting silent renew...
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - BEGIN refresh session Authorize
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - RefreshSession created. Adding myautostate: 28fdc730e4b425df55bd4ff5a60a3a4f23h7sxd6h
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - found refresh code, obtaining new credentials with refresh code
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - Did not find any configured route for route https://*redacted*.com/nidp/oauth/nam/token
    angular-auth-oidc-client.mjs:157 [DEBUG] 0-*redacted client_id* - token refresh response:  {access_token: 'eyJ...', token_type: 'bearer', expires_in: 3599, scope: 'profile roles'}
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - history clean up inactive
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - AuthResult '{
      "access_token": "eyJ...",
      "token_type": "bearer",
      "expires_in": 3599,
      "scope": "profile roles",
      "state": "28fdc730e4b425df55bd4ff5a60a3a4f23h7sxd6h"
    }'.
          AuthCallback created, begin token validation
    angular-auth-oidc-client.mjs:157 [DEBUG] 0-*redacted client_id* - Getting signinkeys from  https://*redacted*.com/nidp/oauth/nam/keys
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - Did not find any configured route for route https://*redacted*.com/nidp/oauth/nam/keys
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - No id_token found, skipping id_token validation
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - authCallback token(s) validated, continue
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - storing the accessToken 'eyJ...'
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - '/api/contact' matches configured route '/'
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - Wanted to add token to /api/contact but found no token: 'null'
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - '/api/navigation/oneplatform' matches configured route '/'
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - Wanted to add token to /api/navigation/oneplatform but found no token: 'null'
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - silent renew, periodic check finished!
    zone.js:2863          GET https://localhost:4200/api/contact 401 (Unauthorized)
    core.mjs:6485 ERROR HttpErrorResponse {headers: HttpHeaders, status: 401, statusText: 'Unauthorized', url: 'https://localhost:4200/api/*redacted*', ok: false, …}
    defaultErrorLogger @ core.mjs:6485
    ...
    zone.js:2863          GET https://localhost:4200/api/navigation/*redacted* 401 (Unauthorized)
    scheduleTask @ zone.js:2863
    ...
    Show 1,054 more frames
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - Checking: silentRenewRunning: false - has idToken: false - has userData: true
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - silent renew, periodic check finished!
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - Checking: silentRenewRunning: false - has idToken: false - has userData: true
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - silent renew, periodic check finished!
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - Checking: silentRenewRunning: false - has idToken: false - has userData: true
    angular-auth-oidc-client.mjs:160 [DEBUG] 0-*redacted client_id* - silent renew, periodic check finished!

ccphelps avatar Apr 22 '22 18:04 ccphelps

Duplicate of #1408 ?

agardiol avatar Apr 25 '22 05:04 agardiol

We fix, add support for this in version 14, PR:

https://github.com/damienbod/angular-auth-oidc-client/pull/1571

damienbod avatar Nov 04 '22 20:11 damienbod

fixed in version 15.0.0

Once released you can configure it something like this:

import { NgModule } from '@angular/core';
import { AuthModule, LogLevel } from 'angular-auth-oidc-client';

@NgModule({
  imports: [
    AuthModule.forRoot({
      config: {
        authority: '--idp--',
        redirectUrl: window.location.origin,
        postLogoutRedirectUri: window.location.origin,
        clientId: '--client_id--',
        scope: 'openid profile offline_access',
        responseType: 'code',
        silentRenew: true,
        useRefreshToken: true,
        ignoreNonceAfterRefresh: true, // this is required if the id_token is not returned
        // allowUnsafeReuseRefreshToken: true, // this is required if the refresh token is not rotated
        triggerRefreshWhenIdTokenExpired: false, // required to refresh the browser if id_token is not updated after the first authentication
        autoUserInfo: false, // if the user endpoint is not supported
        logLevel: LogLevel.Debug,
      },
    }),
  ],
  exports: [AuthModule],
})
export class AuthConfigModule {}

damienbod avatar Nov 06 '22 06:11 damienbod

fixed in v15.0.0

damienbod avatar Nov 18 '22 11:11 damienbod