wi3land / ionic-appauth

Intergration for OpenId/AppAuth-JS into Ionic V3/4/5
MIT License
96 stars 74 forks source link

Notifier is not present on AuthorizationRequest handler. No delivery of result will be possible #323

Closed weihsth closed 4 months ago

weihsth commented 7 months ago

Hi folks, thank you for this great plugin and the effort of adding examples!

I already searched through the open issues and googled a lot, but can not find any helping advices for my bug(?).

Using the capacitor example code the project compiles without errors. Login and redirect (locally) is working well until it comes to calling auth.authorizationCallback(). This always ends up in a dev-tools-termin message like this:

logger.js:34 Checking to see if there is an authorization response to be delivered.
logger.js:34 Notifier is not present on AuthorizationRequest handler. No delivery of result will be possible

My authConfig (KeyCloak) looks like this:

const sharedAuthConfig = {
    client_id: 'web',
    server_host: 'https://auth.my-domain.com/auth/realms/<realm-name>',
    redirect_url: '<app-ident>://auth/callback',
    end_session_redirect_url: '<app-ident>://auth/end-session',
    scopes: 'openid profile email roles offline_access',
    pkce: true, // tested with true and false
};

Client is public and was working with another oidc plugin I used before. I switched to yours because of ionic app support.

auth.factory.ts:

    [...]

    if (!platform.is('cordova')) {
        authService.authConfig.redirect_url = window.location.origin + '/auth/callback';
        authService.authConfig.end_session_redirect_url = window.location.origin + '/auth/end-session';
    }

    [...]

The '/auth/callback' is reached, bot nothing happens on this page. It shoul redirect me to "/home" after checking the auth code. I dont even see any "/token" request in the dev tools, so the auth code is not handled.

I see the callback-URL with all the parameters in the Browser address field. When refreshing the browser, I can see this error event:

{ "action": "Sign In Failed", "error": "Handle Not Available" }

The auth.init() is called in AppComponent constructor after platform.ready(). Also tried to run the init before platform.ready(). Does not matter. From the source code I see, that the notifier should be set up when calling init() funtion. But seems, it does not.

Since I cannot find any advices in documentation about which kind of Notifier or AuthorizationRequest handler is ment, I ask you kindly for giving me any advice, link or example, what I need to adjust.

I checked code a lot of times and even went throgh cordova and other example code. There is nowwhere a setup für this kind of classes.

Regards!

Addendum: Tested with Android (deployed via Android Studio). Redirect to login works. Redirect back to /auth/callback works, but from the $events observable I get this error:

{ "action": "Sign In Failed", "error": "Handle Not Available" }

I looked in the capacitor example code again and can not find any "handle" setup.

weihsth commented 7 months ago

After checking the lib code, I found out, that I am not allowed to set the response_type. For example for lokal development I am always using response_type: 'token', which is also supported by AppAuth-JS. Is there a reason, why this part is hard codet in the module lib source code? Do you plan to change this?

performAuthorizationRequest(authExtras, state) {
        return __awaiter(this, void 0, void 0, function* () {
            let requestJson = {
                response_type: AuthorizationRequest.RESPONSE_TYPE_CODE, // <--- not possible to configure :(
                client_id: this.authConfig.client_id,
                redirect_uri: this.authConfig.redirect_url,
                scope: this.authConfig.scopes,
                extras: authExtras,
                state: state || undefined,
            };
            let request = new AuthorizationRequest(requestJson, new DefaultCrypto(), this.authConfig.pkce);
            if (this.authConfig.pkce)
                yield request.setupCodeVerifier();
            return this.requestHandler.performAuthorizationRequest(yield this.configuration, request);
        });
    }

I am still not able to find out, why this.notifier seems to be undefined here, but I hope someone can provide some hint what I missed during implementation. I compared my code with the capacitor example several times now. It's the same code, but not working. I also tested installing optionalDependencies, but nothing changed so far.

The code, where the initial "error" message is coming from:

/**
* Completes the authorization request if necessary & when possible.
*/
completeAuthorizationRequestIfPossible(): Promise<void> {
    // call complete authorization if possible to see there might
    // be a response that needs to be delivered.
    log(`Checking to see if there is an authorization response to be delivered.`);
    if (!this.notifier) {
      log(`Notifier is not present on AuthorizationRequest handler.
          No delivery of result will be possible`)
    }
    return this.completeAuthorizationRequest().then(result => {
      if (!result) {
        log(`No result is available yet.`);
      }
      if (result && this.notifier) {
        this.notifier.onAuthorizationComplete(result.request, result.response, result.error);
      }
    });
}

How to make sure, this.notifier is set? When I look into the code, it's coming from @openid/appauth module, and I installed this module. I can not find any code in the example, where I need to setup Notifier on my own.

And the redirect works.. I have all the parameters in the redirect URL:

http://localhost:4211/auth/callback?state=PDMlWMczbd&session_state=c4b77657-d12b-462b-b01b-87ad857c9ff8&code=4ef8093d-03ce-43c1-a636-0f1809f7d6aa.c4b77657-d12b-462b-b01b-87ad857c9ff8.a3dfc6d4-7dbd-4f82-b4bb-e5bd17d26446

and I call th needed function in the callback Component:

async ionViewWillEnter() {
    this.sub = this.authService.events$.subscribe((action) => this.handleAuthEvent(action));
    this.authService.authorizationCallback(window.location.origin + this.router.url);
}

Callback Component console log output:

{action: 'Init'}
Checking to see if there is an authorization response to be delivered.
Notifier is not present on AuthorizationRequest handler.
          No delivery of result will be possible
weihsth commented 6 months ago

Hello folks,

is there really noone with any hint why I get errors on the callback page?

Redirect to login-page (keycloak) works, redirekt to callback page (app) works.

But on the callback page I get the error: {"action":"Sign In Failed","error":"Handle Not Available"}

I just need a hint, what I need to install, activate or configure to get this magic "Handle" available. There is no hint in the documentation about this. And I searched through all open and closed Issues in this project without any success.

Testing on a real Android device.

dmoojunk commented 4 months ago

Hey, just had this myself. This notifier is set on auth.init(). After a redirect you need to make sure this has been called before it reaches your callback page. My problem was I was trying to isolate this in a test area and did not have the auth init happening early enough in the sequence. I needed to move the auth init to the app component constructor so notifier existed.

weihsth commented 4 months ago

Thank you for your response @dmoojunk !

I am doing the init() call right after platform.ready(). So that was not the issue.. I fixed it today, after I checked all files again. The real Issue was, that I added AuthService to "prviders: []" list in two different modules. So the init() call was done on the first instance, and the rest on the second instance. Silly mistake I did not do for years :D

It is working now! I added AuthService to AppModule only now. And the imported AuthModule is using this instance.