AzureAD / microsoft-authentication-library-for-js

Microsoft Authentication Library (MSAL) for JS
http://aka.ms/aadv2
MIT License
3.64k stars 2.65k forks source link

How do I get my angular application to work with b2c “revoke session” button which I can press in the Azure portal #2940

Closed zebslc closed 3 years ago

zebslc commented 3 years ago

Library

Description

My use case is to be able to forcibly require users to log in again both from a lost device/account compromised situation but also to update their cached user account which we enrich with additional information in our Angular app.

In Azure B2C I have available several administration buttons including the [Revoke Sessions]. Behind the scenes this calls the graph function as described here (which my API can call programmatically later):- https://docs.microsoft.com/en-us/graph/api/user-revokesigninsessions?view=graph-rest-1.0&tabs=csharp

image

In my Angular application, I cannot get this to force my user to log in again on subsequent calls for secured resources. I am expecting that when I make any call after pressing this button, it would send back a failure code that I could trap in an interceptor or similar.

The documentation is not clear & I am not even sure if I am misinterpreting how the action works. I have looked at various stack overflow answers including one about skewing time and customising the basic SUSI flow but that seems excessive for something which should be a common use case.

I am using your msal-angular-v2/angular11-b2c-sample with changes to point it to my B2C area. This area has standard flows configured as shown below. The issue occurs with the my existing MSAL 1 and your new 2 code - neither seem to work for this.

image

Using this code with my settings, I am able to sign into B2C using the with a created account, edit my profile and view my example secured api.

Within the B2C environment I press the revoke session button. On the client I can edit my profile and call my API again and it just calls it as before without sending me to the login page.

I suspect the change has to go into this part of app.component.ts sample:-

    this.msalBroadcastService.msalSubject$
      .pipe(
        filter((msg: EventMessage) => msg.eventType === EventType.LOGIN_FAILURE || msg.eventType === EventType.ACQUIRE_TOKEN_FAILURE),
        takeUntil(this._destroying$)
      )
      .subscribe((result: EventMessage) => {
        console.log(result);
        if (result.error instanceof AuthError) {
          // Check for forgot password error
          // Learn more about AAD error codes at https://docs.microsoft.com/azure/active-directory/develop/reference-aadsts-error-codes
          if (result.error.message.includes('AADB2C90118')) {

            // login request with reset authority
            let resetPasswordFlowRequest = {
              scopes: ["openid"],
              authority: this.policies.authorities.forgotPassword.authority,
            }

            this.login(resetPasswordFlowRequest);
          }
        }
      });

The documentation with that sample points you to here for other events:- https://docs.microsoft.com/en-gb/azure/active-directory/develop/reference-aadsts-error-codes but again there is nothing mentioned about what to expect from revoke or what I might need to trap to do a force login again.

What am I missing and how can I get the sample application to force someone to log in again when they try to access a protected resource after that button has been pressed?

Thank you

Source

jo-arroyo commented 3 years ago

@nickgmicrosoft Do you have any insight?

JasSuri commented 3 years ago

Unfortunately, this "revoke sessions" is only for Azure AD refresh tokens/cookie revocation. When you ran the "Edit Profile" button, it used the Session Cookies, therefore are not prompted to login again.

For Azure AD B2C, users, it only evaluates the RefreshTokensValidFromDateTime user attribute in User Flows. Custom policies can do that, with further configuration also.

If you delete the Access Token in your Session Data (in the browser), hit the 'Revoke Session' button or call the API, then in the App run AcquireTokenSilent() -> MSAL 2.x

MSAL 1.x

Due to this, you would want to make your Web Session (cookie) lifetime pretty small, and Refresh token lifetime as long as possible. In the case of MSAL.js 2.x, currently RT lifetime is fixed at 24 hours for SPA's.

zebslc commented 3 years ago

@JasSuri @jo-arroyo thank you for that - Do you have any good guidance suggestions for this & how to trap/respond to it from my code/the samples here given it is in the iframe generated by msal? Is it something that you could broadcast potentially?

I am also in the process of setting up our custom flows at the moment because we want to be able to generate an account with a temporary password which the user has to change on first login without the verify email part (as we have already done that to send them a one time password). I would appreciate a hint/any links about which specific flow parts I should change to make this work.

Thank you for your time & the work you are doing on this

JasSuri commented 3 years ago

The usual approach is to handle the normal errors coming back from AAD B2C that are generated by users. Eg

Now a specific error will be introduced by RT revocation, and you might want to handle it explicitly. Based on the same logic of catching the "User has forgotten their password" error, you can add another catch statement for AADB2C90129 | The provided grant has been revoked. Please reauthenticate and try again. See the example here. All errors are documented here.

Then any other error should simply have a global response, eg, redirect the user to the Home Page, or maybe back to Sign In.

zebslc commented 3 years ago

Thank you for that - I will try to implement that change with the above code sample from app.component.ts and let you know if there are any issues but you have given me a good direction to try. The error codes could possibly be better commented in the sample with the link you gave. Kind regards

zebslc commented 3 years ago

Hi @JasSuri , I added the following to my code in the app.component.ts area listed at the start of this question in order to see if there are any events I am missing and after running it.

    // Just take all the messages apart from the success one to see if the revoke appears anywhere
    this.msalBroadcastService.msalSubject$
      .pipe(
        filter((msg: EventMessage) => msg.eventType !== EventType.LOGIN_SUCCESS),
        takeUntil(this._destroying$) )
        .subscribe((result: EventMessage) => {
          console.log('all messages - event type and message', result.eventType, result);
        });

Below is the trace. I have commented on it the point that I pressed the revoke button. I can't see an error - I have tried to log everything. image

Adding the error to where the password reset code is trapped doesn't do anything but I would expect it to be hit - I changed the eventType filter to be more permissive and am trapping everything as above just in case I missed something. Am I misinterpreting how these should be trapped or just doing something stupid? :-D

image

Kind regards

zebslc commented 3 years ago

I am using MSAL 2 btw and the v2 flows - the rest is just the published sample with changes to point to my b2c environment

zebslc commented 3 years ago

Hi, this is still an issue for me - is there any solution or an indication of what I am doing wrong in my last comments?

JasSuri commented 3 years ago

You added this to acquireTokenSilent()? That is where your logic needs to sit.

github-actions[bot] commented 3 years ago

This issue has not seen activity in 14 days. It will be closed in 7 days if it remains stale.

github-actions[bot] commented 3 years ago

This issue has been closed due to inactivity. If this has not been resolved please open a new issue. Thanks!