Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Event 'discovery_document_loaded' is triggered twice, possibly causing nonce validation to fail #1199

Closed
amchavan opened this issue Feb 15, 2022 · 5 comments
Labels
bug For tagging faulty or unexpected behavior. investigation-needed Indication that the maintainer or involved community members may need to investigate more.

Comments

@amchavan
Copy link

amchavan commented Feb 15, 2022

To reproduce

The issue can be verified very simply by editing the sample app in this repo, adding a couple of lines at the beginning of AppComponent.constructor() to log the event

   this.oauthService.events
      .pipe(filter((e) => e.type === 'discovery_document_loaded'))
      .subscribe((e) => console.log( e.type, e['info'] ));

and adding a call to oauthService.initCodeFlow() to AppComponent.configureCodeFlow():

    this.oauthService.configure(authCodeFlowConfig);
    this.oauthService.initCodeFlow();   // ADDED
    this.oauthService.loadDiscoveryDocumentAndTryLogin().then((_) => { ... }

The net effect is, the user cannot login and is redirected to the login page over and over.

Analysis

In oauth-service.ts the discovery_document_loaded event gets published twice, once by loadJwks(), and then again by its caller, loadDiscoveryDocument().

This is probably inefficient but harmless, unless you call initCodeFlow() before invoking loadDiscoveryDocumentAndTryLogin(), as suggested in the "Logging in" section of the README.md file.
The code flow init method (see lines 2706-2708 in oauth-service.ts) subscribes to the discovery_document_loaded event, invoking initCodeFlowInternal() when upon reception.

The nonce is created in the course of the execution of this last method.

If the event is thrown twice:

  • (first event received) A nonce is created
  • The login URL is created, including that nonce
  • The browser is redirected to the login page
  • (second event received) A new nonce overwrites the previous one in the session storage
  • The browser is redirected to the app; the URL includes the previous nonce
  • Nonce validation fails: nonce in the session storage does not match what came back from the Identity Provider

I suggest that the discovery_document_loaded event gets published only once.

@amchavan
Copy link
Author

See also #1125 and #810, which triggered the creation of this ticket.

@jeroenheijmans jeroenheijmans added bug For tagging faulty or unexpected behavior. investigation-needed Indication that the maintainer or involved community members may need to investigate more. labels Feb 15, 2022
@amchavan
Copy link
Author

Removed from problem description:

, or initCodeFlow() is removed: interestingly, calling that method is mentioned in the documentation, but both example applications avoid calling it.

Method initCodeFlow() is indeed called by the sample app, not directly, but by way of initLoginFlow().

While the documentation seems to imply that initCodeFlow() should be called before loadDiscoveryDocumentAndTryLogin(), the samples invert that order, avoiding nonce corruption.

@jeroenheijmans
Copy link
Collaborator

With "the documentation" you mean above-linked README, right? I think it might technically suggest that it's an "either / or" choice, but the way it says so might not be immediately obvious especially to non-native speakers:

After this, you can initialize the code flow using:

this.oauthService.initCodeFlow();

There is also a convenience method initLoginFlow which initializes either the code flow or the implicit flow depending on your configuration.

this.oauthService.initLoginFlow();

The "there is also" part implies that it's an alternative.

It might be good to clarify that point?

@amchavan
Copy link
Author

It's pretty clear (to me, at least) that initLoginFlow() is an alternative to initCodeFlow().
But right after that, the README continues:

Also -- as shown in the readme -- you have to execute the following code...

...which (to me, at least) implies: "after you have initialized the code flow, you'll need to configure the OAuth2 client code and load the discovery document". That's what got me.

Minor note: it may be worth it to remove that "-- as shown in the readme --" fragment, since we are in the README file.

Minor suggestion: it may be worth it to combine configuration and initialization in a single method, something like

public configureAndInitLoginFlow( config: AuthConfig ) { ... }

@manfredsteyer
Copy link
Owner

will be fixed in next version.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug For tagging faulty or unexpected behavior. investigation-needed Indication that the maintainer or involved community members may need to investigate more.
Projects
None yet
Development

No branches or pull requests

3 participants