From 402e4899fef97796bceca2f19be3544d5ffc3674 Mon Sep 17 00:00:00 2001 From: Ben Hovinga <23349127+benhovinga@users.noreply.github.com> Date: Tue, 4 Feb 2025 11:17:20 -0330 Subject: [PATCH 1/8] Add Microsoft Entra ID to OAuth providers list --- docs/pages/data/manifest.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/pages/data/manifest.json b/docs/pages/data/manifest.json index 9c1d79a662..a0e4f4787c 100644 --- a/docs/pages/data/manifest.json +++ b/docs/pages/data/manifest.json @@ -91,6 +91,7 @@ "mastodon": "Mastodon", "mattermost": "Mattermost", "medium": "Medium", + "microsoft-entra-id": "Microsoft Entra ID", "naver": "Naver", "netlify": "Netlify", "notion": "Notion", @@ -146,6 +147,7 @@ "logto", "mastodon", "mattermost", + "microsoft-entra-id", "nextcloud", "okta", "ory-hydra", From fa88ca1fdec618e136ecf2faae0eacbc2a16ffe6 Mon Sep 17 00:00:00 2001 From: Ben Hovinga <23349127+benhovinga@users.noreply.github.com> Date: Tue, 4 Feb 2025 11:19:01 -0330 Subject: [PATCH 2/8] Add Microsoft Entra ID to Issue Template providers dropdown --- .github/ISSUE_TEMPLATE/2_bug_provider.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/ISSUE_TEMPLATE/2_bug_provider.yml b/.github/ISSUE_TEMPLATE/2_bug_provider.yml index d129a423c8..20e6786f05 100644 --- a/.github/ISSUE_TEMPLATE/2_bug_provider.yml +++ b/.github/ISSUE_TEMPLATE/2_bug_provider.yml @@ -70,6 +70,7 @@ body: - "Mail.ru" - "Mastodon" - "Medium" + - "Microsoft Entra ID" - "Naver" - "Netlify" - "NetSuite" From 1a38022575d3304eccec80e407413e04f8d2a891 Mon Sep 17 00:00:00 2001 From: Ben Hovinga <23349127+benhovinga@users.noreply.github.com> Date: Tue, 4 Feb 2025 17:28:47 -0330 Subject: [PATCH 3/8] Fix MicrosoftEntraIDProfile to include all id_token claims and optional claims --- .../core/src/providers/microsoft-entra-id.ts | 324 +++++++++++++++++- 1 file changed, 320 insertions(+), 4 deletions(-) diff --git a/packages/core/src/providers/microsoft-entra-id.ts b/packages/core/src/providers/microsoft-entra-id.ts index be71594493..52fda769be 100644 --- a/packages/core/src/providers/microsoft-entra-id.ts +++ b/packages/core/src/providers/microsoft-entra-id.ts @@ -11,11 +11,327 @@ import { conformInternal, customFetch } from "../lib/symbols.js" import type { OIDCConfig, OIDCUserConfig } from "./index.js" -export interface MicrosoftEntraIDProfile extends Record { - sub: string - nickname: string +/** + * @see [Microsoft Identity Platform - ID token claims reference](https://learn.microsoft.com/en-us/entra/identity-platform/id-token-claims-reference) + * @see [Microsoft Identity Platform - Optional claims reference](https://learn.microsoft.com/en-us/entra/identity-platform/optional-claims-reference) + */ +export interface MicrosoftEntraIDProfile { + /** + * Identifies the intended recipient of the token. In `id_tokens`, the + * audience is your app's Application ID, assigned to your app in the Azure + * portal. This value should be validated. The token should be rejected if it + * fails to match your app's Application ID. + */ + aud: string + /** + * Identifies the issuer, or "authorization server" that constructs and + * returns the token. It also identifies the tenant for which the user was + * authenticated. If the token was issued by the v2.0 endpoint, the URI ends + * in `/v2.0`. The GUID that indicates that the user is a consumer user from + * a Microsoft account is `9188040d-6c67-4c5b-b112-36a304b66dad`. Your app + * should use the GUID portion of the claim to restrict the set of tenants + * that can sign in to the app, if applicable. */ + iss: string + /** Indicates when the authentication for the token occurred. */ + iat: Date + /** + * Records the identity provider that authenticated the subject of the token. + * This value is identical to the value of the issuer claim unless the user + * account isn't in the same tenant as the issuer - guests, for instance. If + * the claim isn't present, it means that the value of `iss` can be used + * instead. For personal accounts being used in an organizational context + * (for instance, a personal account invited to a tenant), the `idp` claim + * may be 'live.com' or an STS URI containing the Microsoft account tenant + * `9188040d-6c67-4c5b-b112-36a304b66dad`. + */ + idp: string + /** + * Identifies the time before which the JWT can't be accepted for processing. + */ + nbf: Date + /** + * Identifies the expiration time on or after which the JWT can't be accepted + * for processing. In certain circumstances, a resource may reject the token + * before this time. For example, if a change in authentication is required + * or a token revocation has been detected. + */ + exp: Date + /** + * The code hash is included in ID tokens only when the ID token is issued + * with an OAuth 2.0 authorization code. It can be used to validate the + * authenticity of an authorization code. To understand how to do this + * validation, see the + * [OpenID Connect specification](https://openid.net/specs/openid-connect-core-1_0.html#HybridIDToken). + * This claim isn't returned on ID tokens from the /token endpoint. + */ + c_hash: string + /** + * The access token hash is included in ID tokens only when the ID token is + * issued from the `/authorize` endpoint with an OAuth 2.0 access token. It + * can be used to validate the authenticity of an access token. To understand + * how to do this validation, see the + * [OpenID Connect specification](https://openid.net/specs/openid-connect-core-1_0.html#HybridIDToken). + * This claim isn't returned on ID tokens from the `/token` endpoint. + */ + at_hash: string + /** + * An internal claim that's used to record data for token reuse. Should be + * ignored. + */ + aio: string + /** + * The primary username that represents the user. It could be an email + * address, phone number, or a generic username without a specified format. + * Its value is mutable and might change over time. Since it's mutable, this + * value can't be used to make authorization decisions. It can be used for + * username hints and in human-readable UI as a username. The `profile` scope + * is required to receive this claim. Present only in v2.0 tokens. + */ + preferred_username: string + /** + * Present by default for guest accounts that have an email address. Your app + * can request the email claim for managed users (from the same tenant as the + * resource) using the `email` + * [optional claim](https://learn.microsoft.com/en-us/entra/identity-platform/optional-claims). + * This value isn't guaranteed to be correct and is mutable over time. Never + * use it for authorization or to save data for a user. If you require an + * addressable email address in your app, request this data from the user + * directly by using this claim as a suggestion or prefill in your UX. On the + * v2.0 endpoint, your app can also request the `email` OpenID Connect + * scope - you don't need to request both the optional claim and the scope to + * get the claim. + */ email: string - picture: string + /** + * The `name` claim provides a human-readable value that identifies the + * subject of the token. The value isn't guaranteed to be unique, it can be + * changed, and should be used only for display purposes. The `profile` scope + * is required to receive this claim. + */ + name: string + /** + * The nonce matches the parameter included in the original authorize request + * to the IDP. If it doesn't match, your application should reject the token. + */ + nonce: string + /** + * The immutable identifier for an object, in this case, a user account. This + * ID uniquely identifies the user across applications - two different + * applications signing in the same user receives the same value in the `oid` + * claim. Microsoft Graph returns this ID as the `id` property for a user + * account. Because the `oid` allows multiple apps to correlate users, the + * `profile` scope is required to receive this claim. If a single user exists + * in multiple tenants, the user contains a different object ID in each + * tenant - they're considered different accounts, even though the user logs + * into each account with the same credentials. The `oid` claim is a GUID and + * can't be reused. + */ + oid: string + /** The set of roles that were assigned to the user who is logging in. */ + roles: string[] + /** An internal claim used to revalidate tokens. Should be ignored. */ + rh: string + /** + * The subject of the information in the token. For example, the user of an + * app. This value is immutable and can't be reassigned or reused. The + * subject is a pairwise identifier and is unique to an application ID. If a + * single user signs into two different apps using two different client IDs, + * those apps receive two different values for the subject claim. You may or + * may not want two values depending on your architecture and privacy + * requirements. + */ + sub: string + /** Represents the tenant that the user is signing in to. For work and school + * accounts, the GUID is the immutable tenant ID of the organization that the + * user is signing in to. For sign-ins to the personal Microsoft account + * tenant (services like Xbox, Teams for Life, or Outlook), the value is + * `9188040d-6c67-4c5b-b112-36a304b66dad`. + */ + tid: string + /** + * Represents an unique identifier for a session and will be generated when a + * new session is established. + */ + sid: string + /** + * Token identifier claim, equivalent to jti in the JWT specification. + * Unique, per-token identifier that is case-sensitive. + */ + uti: string + /** Indicates the version of the ID token. */ + ver: "2.0" + /** + * If present, always true, denoting the user is in at least one group. + * Indicates that the client should use the Microsoft Graph API to determine + * the user's groups + * (`https://graph.microsoft.com/v1.0/users/{userID}/getMemberObjects`). + */ + hasgroups: boolean + /** + * Users account status in tenant. If the user is a member of the tenant, the + * value is `0`. If they're a guest, the value is `1`. + */ + acct: 0 | 1 + /** + * Auth Context IDs. Indicates the Auth Context IDs of the operations that + * the bearer is eligible to perform. Auth Context IDs can be used to trigger + * a demand for step-up authentication from within your application and + * services. Often used along with the `xms_cc` claim. + */ + acrs: string + /** Time when the user last authenticated. */ + auth_time: Date + /** + * User's country/region. This claim is returned if it's present and the + * value of the field is a standard two-letter country/region code, such as + * FR, JP, SZ, and so on. + */ + ctry: string + /** + * IP address. Adds the original address of the requesting client + * (when inside a VNET). + */ + fwd: string + /** + * Optional formatting for group claims. The `groups` claim is used with the + * GroupMembershipClaims setting in the + * [application manifest](https://learn.microsoft.com/en-us/entra/identity-platform/reference-app-manifest), + * which must be set as well. + */ + groups: string + /** + * Login hint. An opaque, reliable login hint claim that's base 64 encoded. + * Don't modify this value. This claim is the best value to use for the + * `login_hint` OAuth parameter in all flows to get SSO. It can be passed + * between applications to help them silently SSO as well - application A can + * sign in a user, read the `login_hint` claim, and then send the claim and + * the current tenant context to application B in the query string or + * fragment when the user selects on a link that takes them to application B. + * To avoid race conditions and reliability issues, the `login_hint` claim + * doesn't include the current tenant for the user, and defaults to the + * user's home tenant when used. In a guest scenario where the user is from + * another tenant, a tenant identifier must be provided in the sign-in + * request. and pass the same to apps you partner with. This claim is + * intended for use with your SDK's existing `login_hint` functionality, + * however that it exposed. + */ + login_hint: string + /** + * Resource tenant's country/region. Same as `ctry` except set at a tenant + * level by an admin. Must also be a standard two-letter value. + */ + tenant_ctry: string + /** + * Region of the resource tenant + */ + tenant_region_scope: string + /** + * UserPrincipalName. An identifier for the user that can be used with the + * `username_hint` parameter. Not a durable identifier for the user and + * shouldn't be used for authorization or to uniquely identity user + * information (for example, as a database key). Instead, use the user object + * ID (`oid`) as a database key. For more information, see + * [Secure applications and APIs by validating claims](https://learn.microsoft.com/en-us/entra/identity-platform/claims-validation). + * Users signing in with an + * [alternate login ID](https://learn.microsoft.com/en-us/entra/identity/authentication/howto-authentication-use-email-signin) + * shouldn't be shown their User Principal Name (UPN). Instead, use the + * following ID token claims for displaying sign-in state to the user: + * `preferred_username` or `unique_name` for v1 tokens and + * `preferred_username` for v2 tokens. Although this claim is automatically + * included, you can specify it as an optional claim to attach other + * properties to modify its behavior in the guest user case. You should use + * the `login_hint` claim for `login_hint` use - human-readable identifiers + * like UPN are unreliable. + */ + upn: string + /** Sourced from the user's PrimaryAuthoritativeEmail */ + verified_primary_email: string[] + /** Sourced from the user's SecondaryAuthoritativeEmail */ + verified_secondary_email: string[] + /** VNET specifier information. */ + vnet: string + /** + * Client Capabilities. Indicates whether the client application that + * acquired the token is capable of handling claims challenges. It's often + * used along with claim `acrs`. This claim is commonly used in Conditional + * Access and Continuous Access Evaluation scenarios. The resource server or + * service application that the token is issued for controls the presence of + * this claim in a token. A value of `cp1` in the access token is the + * authoritative way to identify that a client application is capable of + * handling a claims challenge. For more information, see + * [Claims challenges, claims requests and client capabilities](https://learn.microsoft.com/en-us/entra/identity-platform/claims-challenge?tabs=dotnet). + */ + xms_cc: string + /** + * Boolean value indicating whether the user's email domain owner has been + * verified. An email is considered to be domain verified if it belongs to + * the tenant where the user account resides and the tenant admin has done + * verification of the domain. Also, the email must be from a Microsoft + * account (MSA), a Google account, or used for authentication using the + * one-time passcode (OTP) flow. Facebook and SAML/WS-Fed accounts do not + * have verified domains. For this claim to be returned in the token, the + * presence of the `email` claim is required. + */ + xms_edov: boolean + /** + * Preferred data location. For Multi-Geo tenants, the preferred data + * location is the three-letter code showing the geographic region the user + * is in. For more information, see the + * [Microsoft Entra Connect documentation about preferred data location](https://learn.microsoft.com/en-us/entra/identity/hybrid/connect/how-to-connect-sync-feature-preferreddatalocation). + */ + xms_pdl: string + /** + * User preferred language. The user's preferred language, if set. Sourced + * from their home tenant, in guest access scenarios. Formatted LL-CC + * ("en-us"). + */ + xms_pl: string + /** + * Tenant preferred language. The resource tenant's preferred language, if + * set. Formatted LL ("en"). + */ + xms_tpl: string + /** + * Zero-touch Deployment ID. The device identity used for `Windows AutoPilot`. + */ + ztdid: string + /** IP Address. The IP address the client logged in from. */ + ipaddr: string + /** On-premises Security Identifier */ + onprem_sid: string + /** + * Password Expiration Time. The number of seconds after the time in the + * `iat` claim at which the password expires. This claim is only included + * when the password is expiring soon (as defined by "notification days" in + * the password policy). + */ + pwd_exp: number + /** + * Change Password URL. A URL that the user can visit to change their + * password. This claim is only included when the password is expiring soon + * (as defined by "notification days" in the password policy). + */ + pwd_url: string + /** + * Inside Corporate Network. Signals if the client is logging in from the + * corporate network. If they're not, the claim isn't included. Based off of + * the + * [trusted IPs](https://learn.microsoft.com/en-us/entra/identity/authentication/howto-mfa-mfasettings#trusted-ips) + * settings in MFA. + */ + in_corp: string + /** + * Last Name. Provides the last name, surname, or family name of the user as + * defined in the user object. For example, `"family_name":"Miller"`. + * Supported in MSA and Microsoft Entra ID. Requires the `profile` scope. + */ + family_name: string + /** + * First name. Provides the first or "given" name of the user, as set on the + * user object. For example, `"given_name": "Frank"`. Supported in MSA and + * Microsoft Entra ID. Requires the `profile` scope. + */ + given_name: string } /** From 8712e1206767600e94315ffbf489c9cd53934d4a Mon Sep 17 00:00:00 2001 From: Ben Hovinga <23349127+benhovinga@users.noreply.github.com> Date: Wed, 5 Feb 2025 14:53:45 -0330 Subject: [PATCH 4/8] Fix MicrosoftEntraID TSDoc Clarified the usage of issuer parameter --- .../core/src/providers/microsoft-entra-id.ts | 94 +++++++++++-------- 1 file changed, 56 insertions(+), 38 deletions(-) diff --git a/packages/core/src/providers/microsoft-entra-id.ts b/packages/core/src/providers/microsoft-entra-id.ts index 52fda769be..d382bb683a 100644 --- a/packages/core/src/providers/microsoft-entra-id.ts +++ b/packages/core/src/providers/microsoft-entra-id.ts @@ -335,77 +335,98 @@ export interface MicrosoftEntraIDProfile { } /** + * ### Setup * - * Add Microsoft Entra ID login to your page. + * #### Callback URL * - * ## Setup - * - * ### Callback URL * ``` - * https://example.com/auth/callback/microsoft-entra-id + * https://example.com/api/auth/callback/microsoft-entra-id * ``` * - * ### Configuration + * #### Environment Variables + * + * ```env + * AUTH_MICROSOFT_ENTRA_ID_ID="" + * AUTH_MICROSOFT_ENTRA_ID_SECRET="" + * AUTH_MICROSOFT_ENTRA_ID_ISSUER="https://login.microsoftonline.com//v2.0/" + * ``` * - * @example + * #### Configuration * - * ```ts + * When the `issuer` parameter is omitted it will default to + * `"https://login.microsoftonline.com/common/v2.0/"`. + * This allows any Microsoft account (Personal, School or Work) to log in. + * + * ```typescript * import MicrosoftEntraID from "@auth/core/providers/microsoft-entra-id" * ... * providers: [ * MicrosoftEntraID({ - * clientId: env.AUTH_MICROSOFT_ENTRA_ID_ID, - * clientSecret: env.AUTH_MICROSOFT_ENTRA_ID_SECRET, + * clientId: process.env.AUTH_MICROSOFT_ENTRA_ID_ID, + * clientSecret: process.env.AUTH_MICROSOFT_ENTRA_ID_SECRET, * }), * ] * ... * ``` * - * ### Resources - * - * - [Microsoft Entra OAuth documentation](https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-auth-code-flow) - * - [Microsoft Entra OAuth apps](https://learn.microsoft.com/en-us/entra/identity-platform/quickstart-register-app) - * - * ### To allow specific Active Directory users access: - * - * By default, the Entra ID provider lets the users to log in with any Microsoft account (either Personal, School or Work). + * To only allow your organization's users to log in you will need to configure + * the `issuer` parameter with your Directory (tenant) ID. * - * To only allow your organization's users to log in, you'll need to set the `issuer`, in addition to the client id and secret. + * ```env + * AUTH_MICROSOFT_ENTRA_ID_ISSUER="https://login.microsoftonline.com//v2.0/" + * ``` * - * @example - * ```ts + * ```typescript * import MicrosoftEntraID from "@auth/core/providers/microsoft-entra-id" - * + * ... * providers: [ * MicrosoftEntraID({ - * clientId: env.AUTH_MICROSOFT_ENTRA_ID_ID, - * clientSecret: env.AUTH_MICROSOFT_ENTRA_ID_SECRET, - * issuer: env.AUTH_MICROSOFT_ENTRA_ID_TENANT_ID, + * clientId: process.env.AUTH_MICROSOFT_ENTRA_ID_ID, + * clientSecret: process.env.AUTH_MICROSOFT_ENTRA_ID_SECRET, + * issuer: process.env.AUTH_MICROSOFT_ENTRA_ID_ISSUER, * }), * ] + * ... * ``` * + * ### Resources + * + * - [Microsoft Entra OAuth documentation](https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-auth-code-flow) + * - [Microsoft Entra OAuth apps](https://learn.microsoft.com/en-us/entra/identity-platform/quickstart-register-app) + * * ### Notes * - * Microsoft Entra ID returns the profile picture in an ArrayBuffer, instead of just a URL to the image, so our provider converts it to a base64 encoded image string and returns that instead. See: https://learn.microsoft.com/en-us/graph/api/profilephoto-get?view=graph-rest-1.0&tabs=http#examples. The default image size is 48x48 to avoid [running out of space](https://next-auth.js.org/faq#:~:text=What%20are%20the%20disadvantages%20of%20JSON%20Web%20Tokens%3F) in case the session is saved as a JWT. + * Microsoft Entra ID returns the profile picture in an ArrayBuffer, instead of + * just a URL to the image, so our provider converts it to a base64 encoded + * image string and returns that instead. See: + * https://learn.microsoft.com/en-us/graph/api/profilephoto-get?view=graph-rest-1.0&tabs=http#examples. + * The default image size is 48x48 to avoid + * [running out of space](https://next-auth.js.org/faq#json-web-tokens) + * in case the session is saved as a JWT. * - * By default, Auth.js assumes that the Microsoft Entra ID provider is - * based on the [Open ID Connect](https://openid.net/specs/openid-connect-core-1_0.html) specification. + * By default, Auth.js assumes that the Microsoft Entra ID provider is based on + * the [Open ID Connect](https://openid.net/specs/openid-connect-core-1_0.html) + * specification. * * :::tip * - * The Microsoft Entra ID provider comes with a [default configuration](https://github.com/nextauthjs/next-auth/blob/main/packages/core/src/providers/microsoft-entra-id.ts). - * To override the defaults for your use case, check out [customizing a built-in OAuth provider](https://authjs.dev/guides/configuring-oauth-providers). + * The Microsoft Entra ID provider comes with a + * [default configuration](https://github.com/nextauthjs/next-auth/blob/main/packages/core/src/providers/microsoft-entra-id.ts). + * To override the defaults for your use case, check out + * [customizing a built-in OAuth provider](https://authjs.dev/guides/configuring-oauth-providers). * * ::: * * :::info **Disclaimer** * - * If you think you found a bug in the default configuration, you can [open an issue](https://authjs.dev/new/provider-issue). + * If you think you found a bug in the default configuration, you can + * [open an issue](https://authjs.dev/new/provider-issue). * - * Auth.js strictly adheres to the specification and it cannot take responsibility for any deviation from - * the spec by the provider. You can open an issue, but if the problem is non-compliance with the spec, - * we might not pursue a resolution. You can ask for more help in [Discussions](https://authjs.dev/new/github-discussions). + * Auth.js strictly adheres to the specification and it cannot take + * responsibility for any deviation from the spec by the provider. You can open + * an issue, but if the problem is non-compliance with the spec, we might not + * pursue a resolution. You can ask for more help in + * [Discussions](https://authjs.dev/new/github-discussions). * * ::: */ @@ -447,14 +468,11 @@ export default function MicrosoftEntraID( } return { - id: profile.sub, - name: profile.name, - email: profile.email, + ...profile, image: image ?? null, } }, style: { text: "#fff", bg: "#0072c6" }, - /** Entra ID returns the wrong issuer @see https://github.com/MicrosoftDocs/azure-docs/issues/113944 */ async [customFetch](...args) { const url = new URL(args[0] instanceof Request ? args[0].url : args[0]) if (url.pathname.endsWith(".well-known/openid-configuration")) { From a98c43608d50d33e244b2d18ee14499aa050776b Mon Sep 17 00:00:00 2001 From: Ben Hovinga <23349127+benhovinga@users.noreply.github.com> Date: Thu, 6 Feb 2025 15:26:11 -0330 Subject: [PATCH 5/8] Fix Microsoft Entra ID documentation --- .../providers/microsoft-entra-id.mdx | 108 ++++++++++++------ 1 file changed, 73 insertions(+), 35 deletions(-) diff --git a/docs/pages/getting-started/providers/microsoft-entra-id.mdx b/docs/pages/getting-started/providers/microsoft-entra-id.mdx index 9052a516d5..91368c368e 100644 --- a/docs/pages/getting-started/providers/microsoft-entra-id.mdx +++ b/docs/pages/getting-started/providers/microsoft-entra-id.mdx @@ -47,6 +47,13 @@ https://example.com/auth/callback/microsoft-entra-id ``` + + +```bash +https://example.com/auth/callback/microsoft-entra-id +``` + + ### Environment Variables @@ -57,6 +64,48 @@ AUTH_MICROSOFT_ENTRA_ID_SECRET AUTH_MICROSOFT_ENTRA_ID_ISSUER ``` +### Register Application + +1. Log in to the [Microsoft Entra admin center](https://entra.microsoft.com/). + +2. In the left sidebar, navigate to Identity --> Applications --> App + Registrations. + +3. Click on New registration. + +4. Give your application a name. This name will be displayed to the user when + they log in. + +5. Select the account types you want to allow to log in. The + `AUTH_MICROSOFT_ENTRA_ID_ISSUER` variable will be based on the selection you + make here. + + - **Single tenant only** - Only allow users from your organization.
+ `https://login.microsoftonline.com//v2.0` + + - **Miltitenant** - Allow users from any organization.
+ `https://login.microsoftonline.com/organizations/v2.0` + + - **Miltitenant + Personal** - Allow any Microsoft account (work, school, + personal).
+ `https://login.microsoftonline.com/common/v2.0` + + - **Personal Only** - Only allow personal Microsoft accounts.
+ `https://login.microsoftonline.com/consumers/v2.0` + +6. Set the Redirect URI platform to `web` and the Callback URI for your + application. When developing you will set this to your local host + environment + (example `http://localhost:3000/api/auth/callback/microsoft-entra-id`). + +7. From the application overview page copy the **Application (client) ID** and + paste it in the `AUTH_MICROSOFT_ENTRA_ID_ID` variable. + +8. Navigate to Certificates & secrets and create a new client secret. + +9. Copy the secret value (this will be hidden when you leave this page) and + paste it in the `AUTH_MICROSOFT_ENTRA_ID_SECRET` variable. + ### Configuration @@ -82,12 +131,12 @@ const { handlers, auth, signIn, signOut } = NextAuth({ ```ts filename="/src/routes/plugin@auth.ts" import { QwikAuth$ } from "@auth/qwik" -import Entra from "@auth/qwik/providers/microsoft-entra-id" +import MicrosoftEntraID from "@auth/qwik/providers/microsoft-entra-id" export const { onRequest, useSession, useSignIn, useSignOut } = QwikAuth$( () => ({ providers: [ - Entra({ + MicrosoftEntraID({ clientId: import.meta.env.AUTH_MICROSOFT_ENTRA_ID_ID, clientSecret: import.meta.env.AUTH_MICROSOFT_ENTRA_ID_SECRET, issuer: import.meta.env.AUTH_MICROSOFT_ENTRA_ID_ISSUER, @@ -102,15 +151,19 @@ export const { onRequest, useSession, useSignIn, useSignOut } = QwikAuth$( ```ts filename="/src/auth.ts" import { SvelteKitAuth } from "@auth/sveltekit" -import Entra from "@auth/sveltekit/providers/microsoft-entra-id" -import { env } from "$env/dynamic/private" +import MicrosoftEntraID from "@auth/sveltekit/providers/microsoft-entra-id" +import { + AUTH_MICROSOFT_ENTRA_ID_ID, + AUTH_MICROSOFT_ENTRA_ID_SECRET, + AUTH_MICROSOFT_ENTRA_ID_ISSUER, +} from "$env/static/private" export const { handle, signIn, signOut } = SvelteKitAuth({ providers: [ - Entra({ - clientId: env.AUTH_MICROSOFT_ENTRA_ID_ID, - clientSecret: env.AUTH_MICROSOFT_ENTRA_ID_SECRET, - issuer: process.env.AUTH_MICROSOFT_ENTRA_ID_ISSUER, + MicrosoftEntraID({ + clientId: AUTH_MICROSOFT_ENTRA_ID_ID, + clientSecret: AUTH_MICROSOFT_ENTRA_ID_SECRET, + issuer: AUTH_MICROSOFT_ENTRA_ID_ISSUER, }), ], }) @@ -121,13 +174,13 @@ export const { handle, signIn, signOut } = SvelteKitAuth({ ```ts filename="/src/app.ts" import { ExpressAuth } from "@auth/express" -import Entra from "@auth/express/providers/microsoft-entra-id" +import MicrosoftEntraID from "@auth/express/providers/microsoft-entra-id" app.use( "/auth/*", ExpressAuth({ providers: [ - Entra({ + MicrosoftEntraID({ clientId: process.env.AUTH_MICROSOFT_ENTRA_ID_ID, clientSecret: process.env.AUTH_MICROSOFT_ENTRA_ID_SECRET, issuer: process.env.AUTH_MICROSOFT_ENTRA_ID_ISSUER, @@ -140,30 +193,15 @@ app.use( -### Notes - -1. Allow only Specific Active Directory Users - -- In https://entra.microsoft.com/ select Identity from the left bar menu. -- Next, go to "App Registration" in the left menu, and create a new one. -- 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 - - Only your tenant, all Microsoft tenants, or all Microsoft tenants and public Microsoft accounts (Skype, Xbox, Outlook.com, etc.) -- When asked for a redirection URL, use `https://yourapplication.com/api/auth/callback/microsoft-entra-id` or for development `http://localhost:3000/api/auth/callback/microsoft-entra-id`. -- After your App Registration is created, under "Client Credential" create your Client secret. -- Now copy your: - - Application (client) ID - - Client secret (value) - - Issuer - -In `.env.local` create the following entries: - -``` -AUTH_MICROSOFT_ENTRA_ID_ID= -AUTH_MICROSOFT_ENTRA_ID_SECRET= -AUTH_MICROSOFT_ENTRA_ID_ISSUER=https://login.microsoftonline.com//v2.0 -``` +## Notes -That will default the tenant to use the `common` authorization endpoint. [For more details see here](https://learn.microsoft.com/en-us/entra/identity-platform/v2-protocols#endpoints). +- If the issuer paramater is not set it will default to + `https://login.microsoftonline.com/common/v2.0`. -- Microsoft Entra returns the profile picture in an ArrayBuffer, instead of just a URL to the image, so our provider converts it to a base64 encoded image string and returns that instead. See: https://learn.microsoft.com/en-us/graph/api/profilephoto-get?view=graph-rest-1.0&tabs=http#examples. The default image size is 48x48 to avoid [running out of space](https://next-auth.js.org/faq#:~:text=What%20are%20the%20disadvantages%20of%20JSON%20Web%20Tokens%3F) in case the session is saved as a JWT. +- Microsoft Entra returns the profile picture in an ArrayBuffer, instead of + just a URL to the image, so our provider converts it to a base64 encoded + image string and returns that instead. See + [Microsoft Graph profilePhoto](https://learn.microsoft.com/en-us/graph/api/profilephoto-get?view=graph-rest-1.0&tabs=http#examples). + The default image size is 48x48 to avoid + [running out of space](https://next-auth.js.org/faq#json-web-tokens) in case + the session is saved as a JWT. From 3b65a1b9a42963d1eb63575357a980203a841fa1 Mon Sep 17 00:00:00 2001 From: Ben Hovinga <23349127+benhovinga@users.noreply.github.com> Date: Thu, 6 Feb 2025 17:17:26 -0330 Subject: [PATCH 6/8] Fix unset issuer overriding environment variable --- packages/core/src/providers/microsoft-entra-id.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/core/src/providers/microsoft-entra-id.ts b/packages/core/src/providers/microsoft-entra-id.ts index d382bb683a..047e3da33b 100644 --- a/packages/core/src/providers/microsoft-entra-id.ts +++ b/packages/core/src/providers/microsoft-entra-id.ts @@ -442,7 +442,11 @@ export default function MicrosoftEntraID( ): OIDCConfig { const { profilePhotoSize = 48 } = config - config.issuer ??= "https://login.microsoftonline.com/common/v2.0" + // If issuer is not set, first fallback to environment variable, then + // fallback to /common/ uri. + config.issuer ??= + process.env.AUTH_MICROSOFT_ENTRA_ID_ISSUER || + "https://login.microsoftonline.com/common/v2.0" return { id: "microsoft-entra-id", From 7005e71f9b289c6d1ce34ab919b457e068b32679 Mon Sep 17 00:00:00 2001 From: Ben Hovinga <23349127+benhovinga@users.noreply.github.com> Date: Thu, 6 Feb 2025 20:29:08 -0330 Subject: [PATCH 7/8] Add example of environment variables --- docs/pages/getting-started/providers/microsoft-entra-id.mdx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/pages/getting-started/providers/microsoft-entra-id.mdx b/docs/pages/getting-started/providers/microsoft-entra-id.mdx index 91368c368e..fe40c1711f 100644 --- a/docs/pages/getting-started/providers/microsoft-entra-id.mdx +++ b/docs/pages/getting-started/providers/microsoft-entra-id.mdx @@ -193,6 +193,12 @@ app.use( +```env filename=".env.local" +AUTH_MICROSOFT_ENTRA_ID_ID="" +AUTH_MICROSOFT_ENTRA_ID_SECRET="" +AUTH_MICROSOFT_ENTRA_ID_ISSUER="https://login.microsoftonline.com//v2.0" +``` + ## Notes - If the issuer paramater is not set it will default to From 1f8bd46b0c05126d43fbbe79cff6b768aee1e46a Mon Sep 17 00:00:00 2001 From: Ben Hovinga <23349127+benhovinga@users.noreply.github.com> Date: Fri, 21 Feb 2025 11:46:10 -0330 Subject: [PATCH 8/8] Fix typo in microsoft-entra-id.mdx Co-authored-by: Robin <16273164+robines@users.noreply.github.com> --- docs/pages/getting-started/providers/microsoft-entra-id.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/pages/getting-started/providers/microsoft-entra-id.mdx b/docs/pages/getting-started/providers/microsoft-entra-id.mdx index fe40c1711f..f5accd7176 100644 --- a/docs/pages/getting-started/providers/microsoft-entra-id.mdx +++ b/docs/pages/getting-started/providers/microsoft-entra-id.mdx @@ -83,10 +83,10 @@ AUTH_MICROSOFT_ENTRA_ID_ISSUER - **Single tenant only** - Only allow users from your organization.
`https://login.microsoftonline.com//v2.0` - - **Miltitenant** - Allow users from any organization.
+ - **Multi-tenant** - Allow users from any organization.
`https://login.microsoftonline.com/organizations/v2.0` - - **Miltitenant + Personal** - Allow any Microsoft account (work, school, + - **Multi-tenant + Personal** - Allow any Microsoft account (work, school, personal).
`https://login.microsoftonline.com/common/v2.0`