How to use custom Azure AD scopes? #3006
-
I'm looking into converting a React app to use Next.js. One requirement of this app is that it uses Azure AD to authenticate users via @azure/msal-react. It accesses an external API that is set up to validate against a custom scope defined in Azure AD. To use this API, it needs an access token. I want to call this API on the server to take advantage of SSR. With a custom scope, getting the access token looks something like this with MSAL: const { accessToken } = pca.acquireTokenSilent({ scopes: [ 'api://<identifier>/My.Custom.Scope' ] }) We call this on demand and pass the result as a Bearer token to the API call. Works like a charm. However, I'm having trouble figuring out how to do this with next-auth. I am able to authenticate just fine with the following configuration, and even have it set up to add my access token to the JWT. // pages/api/auth/[...nextauth.js]
import NextAuth from "next-auth";
import AzureAdProvider from "next-auth/providers/azure-ad";
export default NextAuth({
secret: process.env.NEXTAUTH_SECRET,
providers: [
AzureAdProvider({
clientId: process.env.AZURE_AD_CLIENT_ID,
clientSecret: process.env.AZURE_AD_CLIENT_SECRET,
tenantId: process.env.AZURE_AD_TENANT_ID,
}),
],
callbacks: {
async jwt({ token, account }) {
const { picture, ...rest } = token;
if (account) {
rest.accessToken = account.access_token;
}
return rest;
},
},
}); I can then get my access token in const { accessToken } = await getToken({
req: context.req,
secret: process.env.NEXTAUTH_SECRET,
}); However, this access token does not have my custom scope. It has these scopes: If I add it to my config, however: AzureAdProvider({
clientId: process.env.AZURE_AD_CLIENT_ID,
clientSecret: process.env.AZURE_AD_CLIENT_SECRET,
tenantId: process.env.AZURE_AD_TENANT_ID,
authorization: {
params: {
scope: 'api://<identifier>/My.Custom.Scope'
}
}
}) I get the following error upon attempting to sign in:
With MSAL, one has to request tokens custom after the initial login because you cannot mix and match Microsoft/OpenID scopes with custom scopes. But in next-auth, it seems that the token is frozen once it's issued, and it doesn't seem like I can get the initial token with my custom scope because it needs those other scopes to authenticate properly. Is there a way I could request a new token as needed with the custom scope as I do in MSAL? I did look over #2068 but was unsure how I would "sign in" again on the server with the new scope since the server is where I'd to perform the API call. |
Beta Was this translation helpful? Give feedback.
Replies: 7 comments 9 replies
-
Have you found a solution? |
Beta Was this translation helpful? Give feedback.
-
I have implemented same and it worked. I believe your solution lies in how you pass in the scope. AzureADProvider({
clientId: process.env.AZURE_AD_CLIENT_ID || "",
clientSecret: process.env.AZURE_AD_CLIENT_SECRET || "",
tenantId: process.env.AZURE_AD_TENANT_ID,
authorization: {
params: {
scope:
"Calendars.Read Calendars.Read.Shared Calendars.ReadWrite Calendars.ReadWrite.Shared",
},
},
}) The scopes should be separated by spaces if more than one. |
Beta Was this translation helpful? Give feedback.
-
Is it possible fetch two token one for api and one for graph api? |
Beta Was this translation helpful? Give feedback.
-
So after many months of looking at this on and off, I think I came to a solution that works for my use case. Using the I got a prototype working with |
Beta Was this translation helpful? Give feedback.
-
What kind of scopes are you looking for? I pull in Security groups they belong to, so i can define Roles just fine, and I pull in profilephoto. (my scope is "openid profile User.Read email", and the User.Read gives me the security group IDs. Are you looking just to use it for Authentication stuff which is the purpose of next-auth, or are you looking to make it a real MSGraph api? |
Beta Was this translation helpful? Give feedback.
-
We solved the issue by after login calling msal-node with scope and store next-auth store two access token one for graph api another for custom backend. |
Beta Was this translation helpful? Give feedback.
-
This issue still persists in Next-Auth v5, as of now. |
Beta Was this translation helpful? Give feedback.
So after many months of looking at this on and off, I think I came to a solution that works for my use case.
Using the
on-behalf-flow
, we added an endpoint to our API that fetches the user info itself. I can't recall the implementation of that endpoint at the moment, but it calls the Graph API. We can then configure our authentication to only use our custom scope for our API, and call the endpoint we created as our userInfo endpoint.I got a prototype working with
remix
andremix-auth
, so I'm not sure the exact details of how to get it to work withnext-auth
, but this solved our issue. Happy to try and answer any further questions people have about this potential solution.