diff --git a/src/providers/azure-ad-b2c.js b/src/providers/azure-ad-b2c.js index b67111be45..35fba4fed2 100644 --- a/src/providers/azure-ad-b2c.js +++ b/src/providers/azure-ad-b2c.js @@ -1,5 +1,7 @@ export default function AzureADB2C(options) { - const tenant = options.tenantId ? options.tenantId : "common" + const { tenantName, primaryUserFlow } = options + const authorizeUrl = `https://${tenantName}.b2clogin.com/${tenantName}.onmicrosoft.com/${primaryUserFlow}/oauth2/v2.0/authorize` + const tokenUrl = `https://${tenantName}.b2clogin.com/${tenantName}.onmicrosoft.com/${primaryUserFlow}/oauth2/v2.0/token` return { id: "azure-ad-b2c", @@ -9,14 +11,29 @@ export default function AzureADB2C(options) { params: { grant_type: "authorization_code", }, - accessTokenUrl: `https://login.microsoftonline.com/${tenant}/oauth2/v2.0/token`, - authorizationUrl: `https://login.microsoftonline.com/${tenant}/oauth2/v2.0/authorize?response_type=code&response_mode=query`, - profileUrl: "https://graph.microsoft.com/v1.0/me/", - profile(profile) { + accessTokenUrl: tokenUrl, + requestTokenUrl: tokenUrl, + authorizationUrl: `${authorizeUrl}?response_type=code+id_token&response_mode=query`, + profileUrl: 'https://graph.microsoft.com/oidc/userinfo', + idToken: true, + profile: (profile) => { + let name = '' + + if (profile.name) { + // B2C "Display Name" + name = profile.name + } else if (profile.given_name && profile.family_name) { + // B2C "Given Name" & "Surname" + name = `${profile.given_name} ${profile.family_name}` + } else if (profile.given_name) { + // B2C "Given Name" + name = `${profile.given_name}` + } + return { - id: profile.id, - name: profile.displayName, - email: profile.userPrincipalName, + name, + id: profile.oid, + email: profile.emails[0] } }, ...options, diff --git a/src/providers/azure-ad.js b/src/providers/azure-ad.js new file mode 100644 index 0000000000..afdd03db26 --- /dev/null +++ b/src/providers/azure-ad.js @@ -0,0 +1,24 @@ +export default function AzureAD(options) { + const tenant = options.tenantId ?? 'common' + + return { + id: 'azure-ad', + name: 'Azure Active Directory', + type: 'oauth', + version: '2.0', + params: { + grant_type: 'authorization_code' + }, + accessTokenUrl: `https://login.microsoftonline.com/${tenant}/oauth2/v2.0/token`, + authorizationUrl: `https://login.microsoftonline.com/${tenant}/oauth2/v2.0/authorize?response_type=code&response_mode=query`, + profileUrl: 'https://graph.microsoft.com/v1.0/me/', + profile: (profile) => { + return { + id: profile.id, + name: profile.displayName, + email: profile.userPrincipalName + } + }, + ...options + } +} diff --git a/www/docs/providers/azure-ad-b2c.md b/www/docs/providers/azure-ad-b2c.md index 514b90f580..933c2aa553 100644 --- a/www/docs/providers/azure-ad-b2c.md +++ b/www/docs/providers/azure-ad-b2c.md @@ -5,11 +5,7 @@ title: Azure Active Directory B2C ## Documentation -https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow - -## Configuration - -https://docs.microsoft.com/en-us/azure/active-directory-b2c/tutorial-create-tenant +https://docs.microsoft.com/en-us/azure/active-directory-b2c/ ## Options @@ -19,34 +15,86 @@ The **Azure Active Directory Provider** comes with a set of default options: You can override any of the options to suit your own use case. -## Example +## Configuration (Basic) + +Basic configuration sets up Azure AD B2C to return an ID Token. This should be done as a prerequisite prior to running through the Advanced configuration. + +Step 1: Azure AD B2C Tenant +https://docs.microsoft.com/en-us/azure/active-directory-b2c/tutorial-create-tenant + +Step 2: App Registration +https://docs.microsoft.com/en-us/azure/active-directory-b2c/tutorial-register-applications -- In https://portal.azure.com/ -> Azure Active Directory create a new App Registration. -- Make sure to remember / copy - - Application (client) ID - - Directory (tenant) ID -- When asked for a redirection URL, use http://localhost:3000/api/auth/callback/azure-ad-b2c -- Create a new secret and remember / copy its value immediately, it will disappear. +Step 3: User Flow +https://docs.microsoft.com/en-us/azure/active-directory-b2c/tutorial-create-user-flows + +Note: For the step "User attributes and token claims" you might minimally: +- Collect attribute: + - Email Address + - Display Name + - Given Name + - Surname +- Return claim: + - Email Addresses + - Display Name + - Given Name + - Surname + - Identity Provider + - Identity Provider Access Token + - User's Object ID + +## Example In `.env.local` create the following entries: ``` -AZURE_CLIENT_ID= -AZURE_CLIENT_SECRET= -AZURE_TENANT_ID= +AZURE_AD_B2C_TENANT_NAME= +AZURE_AD_B2C_CLIENT_ID= +AZURE_AD_B2C_CLIENT_SECRET= +AZURE_AD_B2C_PRIMARY_USER_FLOW= ``` -In `pages/api/auth/[...nextauth].js` find or add the AZURE entries: +In `pages/api/auth/[...nextauth].js` find or add the AZURE_AD_B2C entries: + +```js +import Providers from 'next-auth/providers'; +... +providers: [ + Providers.AzureADB2C({ + tenantName: process.env.AZURE_AD_B2C_TENANT_NAME, + clientId: process.env.AZURE_AD_B2C_CLIENT_ID, + clientSecret: process.env.AZURE_AD_B2C_CLIENT_SECRET, + primaryUserFlow: process.env.AZURE_AD_B2C_PRIMARY_USER_FLOW, + scope: `offline_access openid`, + }), +] +... + +``` + +## Configuration (Advanced) + +Advanced configuration sets up Azure AD B2C to return an Authorization Token. This builds on the steps completed in the Basic configuration above. + +Step 4: Add a Web API application +https://docs.microsoft.com/en-us/azure/active-directory-b2c/tutorial-single-page-app-webapi?tabs=app-reg-ga + +Note: this is a second app registration (similar to Step 2) but with different setup and configuration. + +## Example + +Nothing in `.env.local` needs to change here. The only update is in `pages/api/auth/[...nextauth].js` where you will need to add the additional scopes that were created in Step 4 above: ```js import Providers from 'next-auth/providers'; ... providers: [ Providers.AzureADB2C({ - clientId: process.env.AZURE_CLIENT_ID, - clientSecret: process.env.AZURE_CLIENT_SECRET, - scope: 'offline_access User.Read', - tenantId: process.env.AZURE_TENANT_ID, + tenantName: process.env.AZURE_AD_B2C_TENANT_NAME, + clientId: process.env.AZURE_AD_B2C_CLIENT_ID, + clientSecret: process.env.AZURE_AD_B2C_CLIENT_SECRET, + primaryUserFlow: process.env.AZURE_AD_B2C_PRIMARY_USER_FLOW, + scope: `https://${process.env.AZURE_AD_B2C_TENANT_NAME}.onmicrosoft.com/api/demo.read https://${process.env.AZURE_AD_B2C_TENANT_NAME}.onmicrosoft.com/api/demo.write offline_access openid`, }), ] ... diff --git a/www/docs/providers/azure-ad.md b/www/docs/providers/azure-ad.md new file mode 100644 index 0000000000..4b2411fbfc --- /dev/null +++ b/www/docs/providers/azure-ad.md @@ -0,0 +1,53 @@ +--- +id: azure-ad +title: Azure Active Directory +--- + +## Documentation + +https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow + +## Configuration + +https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app + +## Example + +### To allow specific Active Directory users access: +- In https://portal.azure.com/ -> Azure Active Directory create a new App Registration. +- Pay close attention to "Who can use this application or access this API?" + - This allows you to scope access to specific types of user accounts. +- Make sure to remember / copy + - Application (client) ID + - Directory (tenant) ID +- When asked for a redirection URL, use http://localhost:3000/api/auth/callback/azure-ad +- Create a new secret and remember / copy its value immediately, it will disappear. + +In `.env.local` create the follwing entries: + +``` +AZURE_AD_CLIENT_ID= +AZURE_AD_CLIENT_SECRET= +AZURE_AD_TENANT_ID= +``` +**Note**: Omit the `AZURE_TENANT_ID` if you created the App Registration for: +> Accounts in any organizational directory (Any Azure AD directory - Multitenant) and personal Microsoft accounts (e.g. Skype, Xbox) + +That will default the tenant to use the `common` authorization endpoint. [For more details see here](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-protocols#endpoints). + +In `pages/api/auth/[...nextauth].js` find or add the `AzureAD` entries: + +```js +import Providers from 'next-auth/providers'; +... +providers: [ + Providers.AzureAD({ + clientId: process.env.AZURE_AD_CLIENT_ID, + clientSecret: process.env.AZURE_AD_CLIENT_SECRET, + tenantId: process.env.AZURE_AD_TENANT_ID, // omit this if it was omitted above. + scope: 'offline_access User.Read', + }), +] +... + +```