Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
196 changes: 196 additions & 0 deletions docs/src/content/docs/(core)/oauth/azure-ad-b2c.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
---
title: Azure AD B2C
description: Add Azure AD B2C authorization provider to Aura Auth for authentication and authorization
---

<Steps>

<Step>

## Azure AD B2C OAuth App

### Register the Application

The first step is to create and register an OAuth App on the Azure AD B2C Applications to obtain access to the user's resources.

</Step>

<Step>

## Installation

Install the package using a package manager like `npm`, `pnpm`, or `yarn`:

```npm
npm install @aura-stack/auth
```

</Step>

<Step>

## Environment setup

Now, you must configure the environment variables required by Aura Auth, including the Azure AD B2C credentials and the encryption secrets.

```bash title=".env" lineNumbers
# Aura Secrets
AURA_AUTH_SECRET="your-32-byte-secret"
AURA_AUTH_SALT="your-32-byte-salt"

# Azure AD B2C Credentials
AURA_AUTH_AZURE_AD_B2C_CLIENT_ID="your_azure_ad_b2c_client_id"
AURA_AUTH_AZURE_AD_B2C_CLIENT_SECRET="your_azure_ad_b2c_client_secret"
```
Comment on lines +36 to +44

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Missing required environment variables for Azure AD B2C tenant and policy.

The provider factory uses URL templates with {tenant} and {policy} placeholders (packages/core/src/oauth/azure-ad-b2c.ts:45-65), but the documentation only lists CLIENT_ID and CLIENT_SECRET. Without AURA_AUTH_AZURE_AD_B2C_TENANT and AURA_AUTH_AZURE_AD_B2C_POLICY (or equivalent configuration), the authorization, token, and metadata endpoints cannot be resolved.

Add these required variables to the environment setup section:

 # Azure AD B2C Credentials
 AURA_AUTH_AZURE_AD_B2C_CLIENT_ID="your_azure_ad_b2c_client_id"
 AURA_AUTH_AZURE_AD_B2C_CLIENT_SECRET="your_azure_ad_b2c_client_secret"
+AURA_AUTH_AZURE_AD_B2C_TENANT="your_azure_ad_b2c_tenant_name"
+AURA_AUTH_AZURE_AD_B2C_POLICY="your_azure_ad_b2c_policy_name"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
```bash title=".env" lineNumbers
# Aura Secrets
AURA_AUTH_SECRET="your-32-byte-secret"
AURA_AUTH_SALT="your-32-byte-salt"
# Azure AD B2C Credentials
AURA_AUTH_AZURE_AD_B2C_CLIENT_ID="your_azure_ad_b2c_client_id"
AURA_AUTH_AZURE_AD_B2C_CLIENT_SECRET="your_azure_ad_b2c_client_secret"
```
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/src/content/docs/`(core)/oauth/azure-ad-b2c.mdx around lines 36 - 44,
The Azure AD B2C setup docs are missing required tenant and policy environment
variables, so the endpoint templates in azure-ad-b2c.ts cannot be resolved.
Update the environment example in the OAuth Azure AD B2C docs to include the
missing AURA_AUTH_AZURE_AD_B2C_TENANT and AURA_AUTH_AZURE_AD_B2C_POLICY
variables alongside CLIENT_ID and CLIENT_SECRET. Make sure the section clearly
matches the placeholders used by the AzureAdB2C provider factory so users can
configure the authorization, token, and metadata URLs correctly.


<Callout type="warn">
**CRITICAL SECURITY WARNING:** The `AURA_AUTH_SECRET` and `AURA_AUTH_SALT` variables are used to encrypt and sign user sessions.
These MUST be securely generated, highly randomized strings consisting of at least 32 bytes to ensure adequate entropy. Never
hardcode these values in your repository. Use a secure generator (like `openssl rand -base64 32`) to create them, and store them
exclusively in your secure environment variables manager.
</Callout>

</Step>

<Step>

## Configure the Auth Instance

Configure the `createAuth` instance inside an `auth.ts` file located at the root of your project. Ensure you explicitly export the `handlers`, `api`, and `jose` objects.

```ts title="auth.ts" lineNumbers
import { createAuth } from "@aura-stack/auth"

export const auth = createAuth({
oauth: ["azure-ad-b2c"],
})

// Extract the required utilities
export const { handlers, api, jose } = auth
```

<Callout type="info">
The `handlers` object contains mapping utilities for standard HTTP methods (`GET`, `POST`, `PATCH`) as well as a unified `ALL`
handler. This allows you to easily mount the authentication routes across any framework (Next.js, Elysia, Express, etc.).
</Callout>

</Step>

<Step>

## Customizing the OAuth Provider

If you need to define custom scopes, change the response type, or map profile data differently, you can use the provider's factory function instead of a simple string identifier.

```ts title="auth.ts" lineNumbers
import { createAuth } from "@aura-stack/auth"
import { azureADB2C } from "@aura-stack/auth/oauth/azure-ad-b2c"

export const auth = createAuth({
oauth: [
azureADB2C({
authorize: {
params: {
// Override default scopes
scope: "read:user user:email",
},
},
}),
],
})

export const { handlers, api, jose } = auth
```
Comment on lines +85 to +103

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Incorrect scope override example uses GitHub OAuth scopes.

The customization example overrides the default scope to "read:user user:email", which are GitHub-specific OAuth scopes. Azure AD B2C uses OpenID Connect scopes like openid, profile, email, and custom application scopes registered in the B2C tenant. Using GitHub scopes in Azure AD B2C documentation will confuse users and cause authorization failures.

Correct the override example to use Azure AD B2C appropriate scopes:

           // Override default scopes
-          scope: "read:user user:email",
+          scope: "openid profile email",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
```ts title="auth.ts" lineNumbers
import { createAuth } from "@aura-stack/auth"
import { azureADB2C } from "@aura-stack/auth/oauth/azure-ad-b2c"
export const auth = createAuth({
oauth: [
azureADB2C({
authorize: {
params: {
// Override default scopes
scope: "read:user user:email",
},
},
}),
],
})
export const { handlers, api, jose } = auth
```
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/src/content/docs/`(core)/oauth/azure-ad-b2c.mdx around lines 85 - 103,
The scope override example in azureADB2C is using GitHub-specific scopes, so
update the example under createAuth/azureADB2C to use Azure AD B2C/OpenID
Connect scopes instead. Replace the authorize.params.scope value with
appropriate B2C scopes such as openid, profile, email, or a tenant-registered
custom scope, and keep the snippet aligned with the auth.ts example shown in the
doc.


</Step>

<Step>

## Sign In to Azure AD B2C (Client & Server)

There are multiple ways to trigger the sign-in flow depending on your ecosystem.

### Sign-in Path (Direct Navigation)

The common route to trigger the auth flow natively without needing a client library is simply navigating the browser to:
`http://localhost:3000/auth/signIn/azure-ad-b2c`

---

### Client-Side (React, Vue, etc.)

You can utilize the `createAuthClient` utility to programmatically trigger sign-ins. You can also define a `redirectTo` destination.

<Callout type="warn">
**Constraint Rule**: The `baseURL` passed into `createAuthClient` MUST exactly match the root domain and path where the HTTP
`handlers` expose their endpoints on the server.
</Callout>

```ts title="components/Login.tsx" lineNumbers
import { createAuthClient } from "@aura-stack/auth/client"

export const authClient = createAuthClient({
baseURL: "http://localhost:3000/auth",
})

const triggerSignIn = async () => {
await authClient.signIn("azure-ad-b2c", {
redirectTo: "/dashboard",
})
}
```

---

### Server-Side (Next.js Actions, Remix Loaders, etc.)

For environments supporting server-side actions, use the programmatic `api.signIn` method securely.

```ts title="actions.ts" lineNumbers
import { api } from "./auth"

export const serverSignIn = async () => {
const response = await api.signIn("azure-ad-b2c", {
redirectTo: "http://localhost:3000/dashboard",
})

// Example returning redirect location
return response.headers.get("Location")
}
```

---

### Session Retrieval

After a user successfully signs in, you can retrieve their session data securely.

**Client-Side:**

```ts
const session = await authClient.getSession()
console.log(session?.user) // The authenticated Azure AD B2C user profile
```

**Server-Side:**

```ts
// Note: You must pass the native Web Request object or Headers!
const session = await api.getSession(request)
console.log(session?.user) // Safely retrieved backend session
```

</Step>

</Steps>

---

## Resources

- [RFC - The OAuth 2.0 Authorization Framework](https://datatracker.ietf.org/doc/html/rfc6749)
- [Azure Active Directory B2C - OAuth 2.0 Provider](https://learn.microsoft.com/en-us/azure/active-directory-b2c/)
- [Azure Active Directory B2C - Authorization Code Flow](https://learn.microsoft.com/en-us/azure/active-directory-b2c/authorization-code-flow)
- [Azure Active Directory B2C - Register a web application](https://learn.microsoft.com/en-us/azure/active-directory-b2c/tutorial-register-applications)
- [Azure Active Directory B2C - Request an access token](https://learn.microsoft.com/en-us/azure/active-directory-b2c/access-tokens)
- [Azure Active Directory B2C - Claims](https://learn.microsoft.com/en-us/azure/active-directory-b2c/tokens-overview#claims)
66 changes: 66 additions & 0 deletions packages/core/src/oauth/azure-ad-b2c.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import type { OAuthProviderCredentials, User } from "@/@types/index.ts"

/**
* @see [Azure Active Directory B2C - Claims](https://learn.microsoft.com/en-us/azure/active-directory-b2c/tokens-overview#claims)
*/
export interface AzureADB2CProfile {
aud: string
iss: string
iat: number
exp: number
nbf: number
ver: string
c_hash: string
at_hash: string
nonce: string
sub: string
acr: string
auth_time: number
scp: string
azp: string
email: string
email_verified: boolean
name: string
given_name: string
family_name: string
preferred_username: string
nickname: string
}

/**
* Azure ActiveDirectory B2C OpenID Connect Provider
*
* > Should set the tenant and policy values in the authorize URL and access token URL.:
* > - https://{tenant}.b2clogin.com/{tenant}.onmicrosoft.com/{policy}/oauth2/v2.0/authorize
* > - https://{tenant}.b2clogin.com/{tenant}.onmicrosoft.com/{policy}/oauth2/v2.0/token
*
* @todo Investigate what does https://fabrikamb2c.b2clogin.com/fabrikamb2c.onmicrosoft.com/b2c_1_sign_in/v2.0/.well-known/openid-configuration URL
*
* @see [Azure Active Directory B2C - OAuth 2.0 Provider](https://learn.microsoft.com/en-us/azure/active-directory-b2c/)
* @see [Azure Active Directory B2C - Authorization Code Flow](https://learn.microsoft.com/en-us/azure/active-directory-b2c/authorization-code-flow)
* @see [Azure Active Directory B2C - Register a web application](https://learn.microsoft.com/en-us/azure/active-directory-b2c/tutorial-register-applications)
* @see [Azure Active Directory B2C - Request an access token](https://learn.microsoft.com/en-us/azure/active-directory-b2c/access-tokens)
* @see [Azure Active Directory B2C - Claims](https://learn.microsoft.com/en-us/azure/active-directory-b2c/tokens-overview#claims)
*/
export const azureADB2C = <DefaultUser extends User = User>(
options?: Partial<OAuthProviderCredentials<AzureADB2CProfile, DefaultUser>>
): OAuthProviderCredentials<AzureADB2CProfile, DefaultUser> => {
return {
id: "azure-ad-b2c",
name: "Azure AD B2C",
authorize: {
url: "https://{tenant}.b2clogin.com/{tenant}.onmicrosoft.com/{policy}/oauth2/v2.0/authorize",
params: { scope: "profile email" },
},
accessToken: "https://{tenant}.b2clogin.com/{tenant}.onmicrosoft.com/{policy}/oauth2/v2.0/token",
userInfo: "https://{tenant}.b2clogin.com/{tenant}.onmicrosoft.com/{policy}/openid-configuration",
profile: (profile) =>
({
sub: profile.sub,
name: profile.name,
email: profile.email,
image: null,
}) as DefaultUser,
...options,
}
}
Loading