Azure / azure-sdk-for-js

This repository is for active development of the Azure SDK for JavaScript (NodeJS & Browser). For consumers of the SDK we recommend visiting our public developer docs at https://docs.microsoft.com/javascript/azure/ or our versioned developer docs at https://azure.github.io/azure-sdk-for-js.
MIT License
2.09k stars 1.2k forks source link

Identity: Unable to log into multiple accounts using the Token Cache #28896

Open Apollo3zehn opened 8 months ago

Apollo3zehn commented 8 months ago

Describe the bug I am developing a VSCode extension and try to use Microsoft Graph to access Outlook resources of two different Microsoft accounts and cache the tokens using the @azure/identity-cache-persistence package (v1.0.0) and the InteractiveBrowserCredential.

With the token cache enabled, I can log into the first account (the browser opens) and give access to an OAuth application to some Outlook resources. I do this by manually calling authenticationRecord = credential.authenticate(...)

Since this is the first log in, no AuthenticationRecord can be provided to the InteractiveBrowserCredential.

Now I try to log into the second account (by setting InteractiveBrowserCredential.loginHint to another value) and again without providing any AuthenticationRecord because it is not available yet. What happens then is that the AuthenticationRecord of the first account is being returned without opening the browser and thus without giving me the chance to log into that second account.

My workaround for now is to disable the token cache when no authentication record is available (i.e. for the first log in) and enable it for all subsequent login attempts. But that leads to the inconvenience that I need to log in twice into every account instead of only once because only for the second log in, the token cache is enabled.

To Reproduce Below is the code that does not work for me, i.e. the token cache is always enabled. Run it twice with different user accounts (set loginHint to a different account each run). Azure Identity will ask the user only once to log in.

const loginHint = `<the Microsoft account>`;
const authenticationRecordFolderPath = path.join(os.homedir(), ".IdentityService");
const authenticationRecordFilePath = path.join(authenticationRecordFolderPath, `cortex_notes@${loginHint}.json`);

let authenticationRecord: AuthenticationRecord | undefined;

try {

    const jsonString = await fs.readFile(authenticationRecordFilePath, {
        encoding: 'utf8'
    });

    authenticationRecord = JSON.parse(jsonString);
} catch (err) {
    // ignore
}

const scopes = ['Mail.ReadWrite', 'Calendars.Read'];

const credential = new InteractiveBrowserCredential({
    tenantId: 'common',
    clientId: 'f470bc86-5748-46ef-8d92-450964420fb9',
    tokenCachePersistenceOptions: {
        enabled: true,
    },
    loginHint: loginHint,
    authenticationRecord: authenticationRecord
});

if (!authenticationRecord) {
    authenticationRecord = await credential.authenticate(scopes);

    try {

        await fs.mkdir(authenticationRecordFolderPath, {
            recursive: true
        });

        let jsonString = JSON.stringify(authenticationRecord);

        await fs.writeFile(authenticationRecordFilePath, jsonString);
    } catch (error) {
        // ignore
    }
}

const authProvider = new TokenCredentialAuthenticationProvider(credential, {
    scopes: scopes,
});

const graphClient = Client.initWithMiddleware({ authProvider: authProvider });

Expected behavior I expect a possibility to enforce authentication, i.e. ignore the token cache, but at the same time update it when the authentication was successful so it is populated when the user needs to authenticate the next time.

More specifically, I would expect that the token cache is (optionally) bypassed when no AuthenticationRecord is available so that the user is forced to authenticate manually.

Screenshots

Additional context

github-actions[bot] commented 8 months ago

@KarishmaGhiya @maorleger

github-actions[bot] commented 8 months ago

Thank you for your feedback. Tagging and routing to the team member best able to assist.