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
- fix: #728 Use same storage regardless of flow in sample The "smart" way to select a different storage type in the sample was causing issues. Sometimes the `setStorage(localStorage)` call would be ma... — committed to jeroenheijmans/angular-oauth2-oidc by jeroenheijmans 3 years ago
- Merge pull request #1046 from jeroenheijmans/728-fix-error-with-sample fix: #728 — committed to manfredsteyer/angular-oauth2-oidc by manfredsteyer 3 years ago
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.
I had the same issue and it turned out that for us using localStorage was the problem.
In my module i had:
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.
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
nonceis 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 thestateparameter. 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, anoncemight 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:
Check both
localStorageandsessionStorage. Most likely the library is findingnullin one storage, when the nonce is actually saved in the other type of storage.Solution in this case: make sure you
setStoragebeforetryLogin. Or consider using Angular’s DI andprovide: 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
noncethat was set.Think of it this way:
nonceinOAuthStoragebefore sending you to the IDS domainnoncein the URL)MemoryStoragebut won’t reload thenonceit knew in step 1noncein 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 1In short, you can not use a full
MemoryStoragesolution forOAuthStorage. You need to use eithersessionStorage,localStorage, or a custom implementation that persists data across redirects (for example cookies or indexdb). Or as an ultimate workaround you could sniff out thekeyand persist specifcallynoncein 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:
provide OAuthStorage first:
maybe this helps someone. 😃
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?