AzureAD / microsoft-authentication-library-for-js

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

AccessToken empty after upgrading to 2.2.0 for ADB2C #2315

Closed dfibuch closed 3 years ago

dfibuch commented 4 years ago

Please follow the issue template below. Failure to do so will result in a delay in answering your question.

Library

Important: Please fill in your exact version number above, e.g. msal@1.1.3.

Framework

Description

After updating to v2.2.0 from v2.1.0 and trying to login using my ADB2C account, the accessToken is not present for either loginRedirect or acquireTokenSilent and I get stuck in a loop of always trying to login.

Using the same code, I have no issues with my ADB2C (Azure AD) app.

Side note: This error is still happening, even though it's been said it should be fixed BrowserAuthError: interaction_in_progress: Interaction is currently in progress. Please ensure that this interaction has been completed before calling an interactive API.

Error Message

image

Security

Regression

MSAL Configuration

image

loginRequest = {
            scopes: ["openid", "profile", "offline_access"]
}

Reproduction steps

Call loginRedirect with your AuthorizationUrlRequest that has scopes on it, sign in with ADB2C account and in your handleRedirectPromise the accessToken is empty.

Expected behavior

Token should be returned as before

Browsers/Environment

JTInfinite commented 3 years ago

hello,

I'm currently stuck on this particular issue and FAQ workarounds don't work for me.

FAQ workaround 1 make no difference. I pass my scope [authorityuri/policy/user.read] in both the loginRedirect and the following acquireTokenSilent - no access_token.

FAQ workaround 2: the account object does not have a username so I am not able to pass a login hint.

When can we expect a fix for this issue?

Thanks

tnorling commented 3 years ago

@JTInfinite

FAQ workaround 1 make no difference. I pass my scope [authorityuri/policy/user.read] in both the loginRedirect and the following acquireTokenSilent - no access_token.

Can you clarify, are you getting an access token back from loginRedirect? If you don't get one from loginRedirect then it is expected you would not get one from a subsequent acquireTokenSilent call, we should understand why. Can you open a new issue with steps to reproduce + send me network logs if this is the case?

FAQ workaround 2: the account object does not have a username so I am not able to pass a login hint.

This is documented here

JTInfinite commented 3 years ago

thanks @tnorling - I've done as you've requested. Let me know if I can help by providing anything further.

Jeff-B1 commented 3 years ago

@tnorling thank you for pointing me here from #2815. Since the core issue is related to the B2C service itself, would it be acceptable to add a change to the MSAL code that associates each cached refresh_token with the scope for which it was requested so that a new auth code would not be required every hour? It would seemingly allow using the workaround listed here and in the FAQ but prevent the need to re-fetch an auth code for a new access token when they expire after 1 hour. (I know it would basically just be a shim fix related to this B2C limitation as the B2C service fix is the desired end goal).

tnorling commented 3 years ago

@Jeff-B1 Unfortunately since B2C is not the only service we support, making this change would break other use cases where this is working as intended. This is a case where we need the services (mainly AAD and B2C) to be aligned. You're always more than welcome to fork the repo to implement a solution that works for you in the interim though. I understand the suggested workaround is far from ideal and this ticket has been open for a while but I appreciate your patience and look forward to sharing good news.

hrc7505 commented 3 years ago

I am having the same issue. Login process working fine. But accessToken is empty.

Here are my configuration and code to handle token and sign in,

const scopes = ["openid", "offline_access"];

const msalConfig: Configuration = {
    auth: {
        knownAuthorities: [policies.signUpSignInAuthority],
        clientId: authConstants.clientId,
        authority: policies.signUpSignInAuthority,
        navigateToLoginRequestUrl: false,
    },
    cache: {
        // This configures where your cache will be stored
        cacheLocation: BrowserCacheLocation.SessionStorage,
        // Set this to "true" to save cache in cookies to address trusted zones limitations in IE
        storeAuthStateInCookie: false,
    },
};

const msalObj = new Msal.PublicClientApplication(msalConfig);

async function loadAuthModule(): Promise<void> {
    try {
        const response = await msalObj.handleRedirectPromise();
        if (response) {
            // Response handling
            handleResponse(response);
        } else {
            signIn();
        }
    } catch (err) {
        // Handling errors here
    }
}

function signIn(): void {
    void msalObj.loginRedirect({
        scopes: scopes,
    });
}

async function getTokenRedirect(): Promise<void> {
    const tokenRequest: Msal.SilentRequest = {
        scopes: scopes,
        account: msalObj.getAccountByHomeId(accountID) as Msal.AccountInfo
    };

    try {
        const response = await msalObj.acquireTokenSilent(tokenRequest);
        console.log(response);
    } catch (error) {
        // Fallback to interaction when silent call fails.
        return msalObj.acquireTokenRedirect(tokenRequest);
    }
}

Here is the response I am getting from the acquireTokenSilent

{
    "authority": ***********,
    "uniqueId": ***********,
    "tenantId": ***********,
    "scopes": [],
    "account": {
        "homeAccountId": ***********,
        "environment": ***********,
        "tenantId": ***********,
        "username": "",
        "localAccountId": ***********,
        "idTokenClaims": {
            "exp": 1612332546,
            "nbf": 1612328946,
            "ver": "1.0",
            "iss": ***********,
            "sub": ***********,
            "aud": ***********,
            "acr": "b2c_1a_signup_signin",
            "nonce": ***********,
            "iat": 1612328946,
            "auth_time": 1612328785,
            "email": "***********@***.com",
            "tid": ***********,
        }
    },
    "idToken": ***********,
    "idTokenClaims": {
        "exp": 1612332546,
        "nbf": 1612328946,
        "ver": "1.0",
        "iss": ***********,
        "sub": ***********,
        "aud": ***********,,
        "acr": "b2c_1a_signup_signin",
        "nonce": ***********,,
        "iat": 1612328946,
        "auth_time": 1612328785,
        "email": "***********@***.com",
        "tid": ***********,
    },
    "accessToken": "",
    "fromCache": false,
    "expiresOn": null,
    "familyId": "",
    "tokenType": "",
    "state": "",
    "cloudGraphHostName": "",
    "msGraphHost": ""
}

Am I missing anything here?

digitalcraftco commented 3 years ago

@hrc7505 Try passing in the Application (client) ID of the app registered in B2C portal to the scopes array. Not sure of the ramifications or why this works but it worked for me. I think you need to expose an API and add a custom scope for a resource if you don't want to pass the clientId to get an accessToken for that resource otherwise.

scopes: ['openid', 'offline_access', XXXXXX-XXXXXXXX-XXXXXXXXXX],

zzzachzzz commented 3 years ago

@digitalcraftco This solution also worked for me. Either the client ID, or a custom scope can be used. I'm using B2C to secure access to an API, so I created a custom scope for a separate registered app for the API.
https://docs.microsoft.com/en-us/azure/active-directory-b2c/access-tokens#scopes

hrc7505 commented 3 years ago

@digitalcraftco This worked for me too. Thank you so much!

pkanher617 commented 3 years ago

Thanks to everyone who pitched in here. Can I close this issue as the workaround mentioned above seems to be working?

Jernik commented 3 years ago

Thanks to everyone who pitched in here. Can I close this issue as the workaround mentioned above seems to be working?

Has that workaround been documented anywhere other than this issue?

Also, is there an update on an actual solution?

pkanher617 commented 3 years ago

The FAQ for the original issue has been added. I'll work on adding docs for this, and will leave this open while I update the FAQ with the workaround to add the custom scope for the web api. We are still waiting to hear back from the B2C team on a comprehensive solution to this.

dfibuch commented 3 years ago

Thanks to everyone who pitched in here. Can I close this issue as the workaround mentioned above seems to be working?

Yeah no problem, though if possible please somehow link this issue when it's fixed so we know it has been addressed.

tnorling commented 3 years ago

All, thanks for your patience. I've just received word from the B2C service team that the fix/feature for this issue is currently rolling out to production tenants and should complete over the next few days. If you're currently using the ssoSilent workaround please try updating your code to just call acquireTokenSilent over the next few days and let us know if you're getting back the access tokens as expected.

dfibuch commented 3 years ago

All, thanks for your patience. I've just received word from the B2C service team that the fix/feature for this issue is currently rolling out to production tenants and should complete over the next few days. If you're currently using the ssoSilent workaround please try updating your code to just call acquireTokenSilent over the next few days and let us know if you're getting back the access tokens as expected.

Fantastic! I am currently off this project but will address it once back on. Thank you for the update.

tnorling commented 3 years ago

Closing as the feature has completed rollout. Please open a new issue if anything else comes up. Thanks!