angular-oauth2-oidc: Validating access_token failed, wrong state/nonce

I’ve integrated OAuth Implicit flow in Angular 8 App, I’ve been getting below issue initial time especially in Firefox (incognito).

Validating access_token failed, wrong state/nonce

Initial time, there is no nonce in the local storage, how can it validateNonce (angular-oauth2-oidc.js - 2358 line) execute? This method is being thrown an exception initial time.

if (this.configService.auth) {
            console.log(this.configService.auth.authRedirectUri + "*&&&&&&&&&&&&&&&&&&dd");
            this.authConfig = {
                issuer: 'https://login.microsoftonline.com/XXXXXX/v2.0',
                redirectUri: this.configService.auth.authRedirectUri,
                clientId: this.configService.auth.clientId,
                scope: 'openid profile email',
                strictDiscoveryDocumentValidation: false,
                oidc: true,
                showDebugInformation: true,
                // URL of the SPA to redirect the user after silent refresh
                // silentRefreshRedirectUri: window.location.origin + '/login.html',
            };
            this.oauthService.configure(this.authConfig);
            this.oauthService.setStorage(localStorage);
            this.oauthService.tokenValidationHandler = new JwksValidationHandler();
            this.oauthService.setupAutomaticSilentRefresh();
            // this.oauthService.silentRefreshRedirectUri = window.location.origin + '/login.html';
        }

// trylogin funtion

  tryLogin(state?: any): Observable<boolean | any> {
        console.log("***********Try Login", state);
        return Observable.create(observer => {
            return this.oauthService.loadDiscoveryDocument(this.configService.auth.openIdDocument).then(() => {
                console.log("***********Try Login", state);
                return this.oauthService.tryLogin({}).then(() => {
                    observer.next(state ? state : this.isLoggedIn);
                    observer.complete();
                }).catch(err => {
                    observer.error(err);
                    observer.complete();
                });
            });
        });
    } 

Desktop (please complete the following information):

  • OS: Mac, Windows
  • Browser Firefox
  • Version Latest

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 4
  • Comments: 41 (2 by maintainers)

Commits related to this issue

Most upvoted comments

I wrote a workaround that stores the nonce and pkce verifier in localstorage. I would like to understand what’s going on and why only firefox. I suspect maybe firefox handels localhost differently. Anyhow I implemented the OAuthStorage class like this and provided it in my core module.

export class LocalNonceStorage implements OAuthStorage {
   private needsLocal(key: string) {
        return key === 'nonce' || key === 'PKCE_verifier';
    }
    getItem(key: string) {
        if (this.needsLocal(key)) {
            return localStorage.getItem(key);
        }
        return sessionStorage.getItem(key);
    }
    removeItem(key: string) {
        if (this.needsLocal(key)) {
            return localStorage.removeItem(key);
        }
        return sessionStorage.removeItem(key);
    }
    setItem(key: string, data: string) {
        if (this.needsLocal(key)) {
            return localStorage.setItem(key, data);
        }
        return sessionStorage.setItem(key, data);
    }
}

export function storageFactory(localNonceStorage: LocalNonceStorage): OAuthStorage {
    return localNonceStorage;
}

export class CoreModule {
    static forRoot(): ModuleWithProviders<CoreModule> {
        return {
            ngModule: CoreModule,
            providers: [        
                { provide: LocalNonceStorage, useClass: LocalNonceStorage },
                { provide: AuthConfig, useValue: authConfig },
                { provide: OAuthModuleConfig, useValue: authModuleConfig },
                { provide: OAuthStorage, useFactory: storageFactory, deps: [LocalNonceStorage] }]
        };
    }

    constructor(@Optional() @SkipSelf() parentModule: CoreModule) {
        if (parentModule) {
            throw new Error('CoreModule is already loaded. Import it in the AppModule only');
        }
    }
}

I had the same issue and it turned out that for us using localStorage was the problem.

In my module i had:

        providers: [
...
          { 
            provide: OAuthStorage, 
            useValue: localStorage 
          }
        ]

The library then seems to mix session and localStorage resulting in the nonce being retrived from the “wrong” one. Seems like a bug to me, if the provider is set to local, all storage should be set/retrieved from local.

We swiched to sessionStorage (the default) and it works fine now. (version 9.0.1)

EDIT: I managed to get it to work using https://github.com/manfredsteyer/angular-oauth2-oidc/issues/728#issuecomment-590909947. This should still be fixed or documented somewhere that it is necessary.

The ability to disable the nonce check might not be feasible, If I recall correctly it’s mandatory by the spec?

Certainly there should be either:

* no error (i.e. there might still be a bug in the library)

* a _descriptive_ error explaining that something was misconfigured in the _app_, in a way that helps resolve the issue

However, I am thinking about closing this specific issue. The original poster never responded anymore or tried Manfred’s suggestion. Others commenting later about having the same symptom might or might not experience the same cause, but we have no up to date reproducible scenario. So it might be better if someone opens a fresh issue with a reproducible scenario using the latest version of the library (or at the least post one in this issue), so we can trace the cause and fix that?

Again, by no means do I want to say that “there’s no issue”, I’m just looking for the clearest, most efficient path to getting a repro, and ultimately getting things resolved.

Just created a fresh project using angular CLI and followed the minimal example and getting this error. The local storage is empty (no state stored). So this is definitely a bug. Currently I am testing on localhost.

The nonce is not mandatory in OIDC and definitely not in RFC 6749. Not sure about the current security BCP draft right now. Anyway. Still a bug no matter how the plugin handles and interprets the state parameter. But basically it currently enforces the use of a nonce which is piggybacked in the state leading to the error due to the bug.

Thanks for all the efforts. Can the fix be merged and released?

Thx @synth3, I’ve traced the problem in the sample application and will add a PR to fix it there.

This also strengthens my suspicion as to what other people in this thread are experiencing.


⚠ Important: read this if you have the same symptoms!

Most likely you have the same problem as the sample application has. If you configure setStorage(...) at incorrect times, a nonce might get stored in a different storage than is used when validating when you get back to your app.

The easy way to validate if this is happening to you, is if you get an error similar to:

Validating access_token failed, wrong state/nonce. null V2Q4NmdvUU13WWVOMzc0RHpWMWRrRTVLSG9sRTlNaG1EZkt3a2RZdF9zRFhf

Check both localStorage and sessionStorage. Most likely the library is finding null in one storage, when the nonce is actually saved in the other type of storage.

Solution in this case: make sure you setStorage before tryLogin. Or consider using Angular’s DI and provide: OAuthStorage.

Another (dirty!) way to check if you have this problem is by doing (this.oauthService as any).saveNoncesInLocalStorage = true; as early as possible. Do not rely on this as a solution though, as you’re abusing a protected feature that’s intended to handle an MSIE bug.

Also, I personally prefer a different approach, which you can try in your app to solve the issue. It relies on using Angular DI to provide storage and config, and a very specific login sequence.


If you still believe you have the same symptom but a different root cause: please open a fresh issue, but do include precise steps to reproduce the issue. That way we can trace any further bugs. Thanks!!

Hi @jeroenheijmans - some time ago I posted how I could reproduce the issue with the sample app: https://github.com/manfredsteyer/angular-oauth2-oidc/issues/728#issuecomment-722987671

⚠️ This comment is a specific reply, about the code in previous post. Not a general remark about the library.

@manandkumaar Well that makes sense. Both Implicit and Code flow include a redirect. After the redirect your Storage implementation will have ‘lost’ the nonce that was set.

Think of it this way:

  1. You’re starting a login sequence. The browser will store a nonce in OAuthStorage before sending you to the IDS domain
  2. You’re at the IDS domain, log in, and get redirected back to the Angular application (with nonce in the URL)
  3. The application reloads a fresh instance of your MemoryStorage but won’t reload the nonce it knew in step 1
  4. The login flow tries to complete, sees the nonce in the URL as passed along by IDS (this is a security check) and tries to compare it to whatever the Angular app saved in step 1
  5. Comparison fails!

In short, you can not use a full MemoryStorage solution for OAuthStorage. You need to use either sessionStorage, localStorage, or a custom implementation that persists data across redirects (for example cookies or indexdb). Or as an ultimate workaround you could sniff out the key and persist specifcally nonce in more persistent storage.

Hope that helps!

I believe I have found the root problem for this issue. It seems to be related to prefetching in Chrome. I have posted a detailed comment on this currently open issue in the Chromium project: https://issues.chromium.org/issues/40940701

I ran into this too. Specifically the user clicking on the link in a registration confirmation email using Firefox and Keycloak caused the Validating access_token failed, wrong state/nonce. error. Chrome was working fine.

What fixed this was changing the order of the providers array in the Module that configures the OAuthModule. Moving the OAuthStorage provider in the first position.

Referring to this sample: https://github.com/jeroenheijmans/sample-angular-oauth2-oidc-with-auth-guards/blob/f0d6f99ba82dbe774710064c7af4631df4420713/src/app/core/core.module.ts#L32-L34 - move line 34 above line 32.

So Instead of:

export class CoreModule {
  static forRoot(): ModuleWithProviders<CoreModule> {
    return {
      ngModule: CoreModule,
      providers: [
        { provide: AuthConfig, useValue: authConfig },
        { provide: OAuthModuleConfig, useValue: authModuleConfig },
        { provide: OAuthStorage, useFactory: storageFactory },
      ]
    };
  }
}

provide OAuthStorage first:

export class CoreModule {
  static forRoot(): ModuleWithProviders<CoreModule> {
    return {
      ngModule: CoreModule,
      providers: [
        { provide: OAuthStorage, useFactory: storageFactory },  // change here!
        { provide: AuthConfig, useValue: authConfig },
        { provide: OAuthModuleConfig, useValue: authModuleConfig },
      ]
    };
  }
}

maybe this helps someone. 😃

any update

Ermmm, it’s been no more than 20 hours since you initially posted 😅 - there’s not a large community here so it might take way longer to get an answer for questions. If you need faster feedback you could try Stack Overflow (they tend to have strict(er) rules about what you need to provide in a question for it to be answerable), or a colleague or paid consultant…

As a footnote, after glancing at your code, I can mention I had more success by providing configuration and storage options via the module, you could try if that helps fix your issue?