Description
openedon May 24, 2022
Hi from the Microsoft Graph SDKs team 👋
We're in the process of implementing CAE in our SDKs, which rely on Azure identity.
First, the GetTokenOptions interface doesn't expose a "claims" property, when the dotnet equivalent does as well as the Java equivalent. This is a limitation for us as we're only taking a dependency on core-auth in an effort to release only as often as needed and to give more control to customers over which azure-identity version they want to use. It's only defined in CredentialFlowGetTokenOptions which as far as I understand is only meant to be used by azure identity to interface with MSAL.
Now, if we force set the claim by doing something like (options as any).claims = claimsValue;
the client with a device code flow still doesn't get a new challenge prompt when the session is revoked.
As per the claims value, from reading the code I understood the claims value expects the JSON representation (base64 decode the claim value from the response header, but do not JSON parse it).
Here are my questions:
- Can you confirm CAE with device code flow works with this JS lib? (it does for Java and dotnet)
- Can you confirm we're passing the right value? (base64 decoded, but not JSON parsed)
- Could you move the claims property to the GetTokenOptions interface?
- Could you validate the following repro is correctly configured?
const getClaimsFromResponse = (response: Response ) => {
if (response.status === 401) {
const rawAuthenticateHeader = response.headers.get("WWW-Authenticate");
if (rawAuthenticateHeader && /^Bearer /gi.test(rawAuthenticateHeader)) {
const rawParameters = rawAuthenticateHeader.replace(/^Bearer /gi, "").split(",");
for (const rawParameter of rawParameters) {
const trimmedParameter = rawParameter.trim();
if (/claims="[^"]+"/gi.test(trimmedParameter)) {
return trimmedParameter.replace(/claims="([^"]+)"/gi, "$1");
}
}
}
}
return undefined;
};
const tokenCredentials = new DeviceCodeCredential(
{
tenantId: '<tid>',
clientId: '<cid>',
userPromptCallback: (info) => console.log(info.message),
});
let previousClaims: string | undefined = undefined;
while(true) {
const token = await tokenCredentials.getToken(["User.Read"], {claims: (previousClaims ? Buffer.from(previousClaims, "base64").toString(): undefined)} as any as GetTokenOptions)
const previousResponse = await fetch("https://graph.microsoft.com/v1.0/me", {headers: {Authorization: `Bearer ${token.token}`}});
previousClaims = getClaimsFromResponse(previousResponse);
console.log("result", await previousResponse.text());
await new Promise(resolve => setTimeout(resolve, 10000));
}