# OAuth 2.0 Flows

This document provides an illustration of OAuth 2.0 authentication flows supported by Microsoft Entra ID.

**Note:** All the following implementation steps are for illustration purposes. It's always recommended to use a library to handle the authentication flow.

## Authorization Code Flow

### Flow Steps

```
1. User → App: Navigate to app's web UI
2. App → User: Redirect to Microsoft login
3. User → Entra ID: Authenticate & consent
4. Entra ID → App: Authorization code (via redirect URI)
5. App → Entra ID: Exchange code for tokens (with client secret)
6. Entra ID → App: Access token + refresh token + ID token
7. App → API: Call API with access token
```

### Implementation Steps

#### 1. Build Authorization URL

```
https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize?
  client_id={application_id}
  &response_type=code
  &redirect_uri={redirect_uri}
  &response_mode=query
  &scope={scopes}
  &state={random_state}
```

**Parameters:**
- `tenant`: Your tenant ID or `common` for multi-tenant
- `client_id`: Application (client) ID from app registration
- `redirect_uri`: Must match exactly what's registered
- `scope`: Space-separated permissions (e.g., `openid profile User.Read`)
- `state`: Random value to prevent CSRF attacks

#### 2. User Authenticates

User is redirected to Microsoft login page, authenticates, and grants consent.

#### 3. Receive Authorization Code

App receives callback at redirect URI:
```
https://your-app.com/callback?
  code={authorization_code}
  &state={state_value}
```

**Validation:**
- Verify `state` matches what you sent
- Extract `code` parameter

#### 4. Exchange Code for Tokens

```http
POST https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded

client_id={application_id}
&scope={scopes}
&code={authorization_code}
&redirect_uri={redirect_uri}
&grant_type=authorization_code
&client_secret={client_secret}
```

**Response:**
```json
{
  "access_token": "eyJ0eXAi...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "M.R3_BAY...",
  "id_token": "eyJ0eXAi..."
}
```

#### 5. Use Access Token

```http
GET https://graph.microsoft.com/v1.0/me
Authorization: Bearer {access_token}
```

## Authorization Code Flow with PKCE

PKCE (Proof Key for Code Exchange) adds security for public clients that cannot securely store a client secret.

### Flow Steps

```
1. App: Generate code verifier (random string)
2. App: Generate code challenge (SHA256 hash of verifier)
3. App → Entra ID: Authorization request with code challenge
4. User → Entra ID: Authenticate & consent
5. Entra ID → App: Authorization code
6. App → Entra ID: Exchange code + code verifier for token
7. Entra ID: Validates verifier matches challenge
8. Entra ID → App: Access token + ID token
```

### Implementation Steps

#### 1. Generate PKCE Values

**Code Verifier:** 43-128 character random string
```javascript
// JavaScript example
const codeVerifier = generateRandomString(128);
```

**Code Challenge:** Base64URL-encoded SHA256 hash of verifier
```javascript
const codeChallenge = base64URLEncode(sha256(codeVerifier));
```

#### 2. Build Authorization URL

```
https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize?
  client_id={application_id}
  &response_type=code
  &redirect_uri={redirect_uri}
  &scope={scopes}
  &state={state}
  &code_challenge={code_challenge}
  &code_challenge_method=S256
```

#### 3. Exchange Code for Tokens (No Secret)

```http
POST https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded

client_id={application_id}
&scope={scopes}
&code={authorization_code}
&redirect_uri={redirect_uri}
&grant_type=authorization_code
&code_verifier={code_verifier}
```

## Client Credentials Flow

### Flow Steps

```
1. App → Entra ID: Request token with client ID + secret
2. Entra ID: Validate credentials
3. Entra ID → App: Access token (application permissions)
4. App → API: Call API with token
```

### Implementation Steps

#### 1. Configure Application Permissions

In app registration:
1. Go to "API permissions"
2. Add **Application** permissions (not delegated)
3. Grant admin consent (required for app permissions)

**Example permissions:**
- `User.Read.All` (application) - Read all users
- `Directory.Read.All` (application) - Read directory

#### 2. Request Access Token

```http
POST https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded

client_id={application_id}
&scope=https://graph.microsoft.com/.default
&client_secret={client_secret}
&grant_type=client_credentials
```

**Parameters:**
- `scope`: Use `{resource}/.default` format
  - For Microsoft Graph: `https://graph.microsoft.com/.default`
  - For your API: `api://{api_app_id}/.default`

**Response:**
```json
{
  "access_token": "eyJ0eXAi...",
  "token_type": "Bearer",
  "expires_in": 3599
}
```

#### 3. Use Access Token

```http
GET https://graph.microsoft.com/v1.0/users
Authorization: Bearer {access_token}
```

## Device Code Flow

**Use for:** Devices without browsers (IoT, CLIs), headless environments

### Flow Steps

```
1. App → Entra ID: Request device code
2. Entra ID → App: Device code + user code + verification URL
3. App → User: Display code and URL
4. User: Opens URL on another device, enters code
5. User → Entra ID: Authenticates & consents
6. App → Entra ID: Poll for token
7. Entra ID → App: Access token (after user completes auth)
```

### Implementation Steps

#### 1. Request Device Code

```http
POST https://login.microsoftonline.com/{tenant}/oauth2/v2.0/devicecode
Content-Type: application/x-www-form-urlencoded

client_id={application_id}
&scope={scopes}
```

**Response:**
```json
{
  "user_code": "GTHK-QPMN",
  "device_code": "GMMhmHCXhWEzkobqIHGG_EnNYYsAkukHspeYUk9E8",
  "verification_uri": "https://microsoft.com/devicelogin",
  "expires_in": 900,
  "interval": 5,
  "message": "To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code GTHK-QPMN to authenticate."
}
```

#### 2. Display Instructions to User

```
To sign in, open https://microsoft.com/devicelogin
and enter code: GTHK-QPMN
```

#### 3. Poll for Token

```http
POST https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded

client_id={application_id}
&grant_type=urn:ietf:params:oauth:grant-type:device_code
&device_code={device_code}
```

**Poll every 5 seconds (use `interval` from response)**

**Pending Response (user hasn't completed auth yet):**
```json
{
  "error": "authorization_pending",
  "error_description": "AADSTS70016: Pending end-user authorization..."
}
```

**Success Response:**
```json
{
  "access_token": "eyJ0eXAi...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "M.R3_BAY...",
  "id_token": "eyJ0eXAi..."
}
```

## Refresh Token Flow

**Use for:** Refreshing expired access tokens without re-authentication

### When to Refresh

- Access tokens typically expire in 1 hour
- Refresh tokens are long-lived (14-90 days)
- Refresh before access token expires for seamless UX

### Implementation

```http
POST https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded

client_id={application_id}
&scope={scopes}
&refresh_token={refresh_token}
&grant_type=refresh_token
&client_secret={client_secret}
```

**Note:** `client_secret` only required for confidential clients

**Response:**
```json
{
  "access_token": "eyJ0eXAi...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "M.R3_BAY...",
  "id_token": "eyJ0eXAi..."
}
```

**Important:** New refresh token is returned; use it for next refresh

## Token Types

### Access Token

- Used to call APIs
- Contains claims (user ID, permissions, etc.)
- Short-lived (typically 1 hour)
- Format: JWT (JSON Web Token)

**Sample claims:**
```json
{
  "aud": "https://graph.microsoft.com",
  "iss": "https://sts.windows.net/{tenant}/",
  "sub": "{user_object_id}",
  "scp": "User.Read Mail.Read",
  "exp": 1680000000
}
```

### Refresh Token

- Used to get new access tokens
- Long-lived (days to months)
- Opaque string (not JWT)
- Single-use (new one issued with each refresh)

### ID Token

- Contains user identity information
- Used by the app to authenticate user
- Format: JWT

**Sample claims:**
```json
{
  "sub": "{user_object_id}",
  "name": "Jane Doe",
  "preferred_username": "jane@contoso.com",
  "email": "jane@contoso.com",
  "oid": "{object_id}"
}
```

## Scopes and Permissions

### Scope Format

**Microsoft Graph:**
```
https://graph.microsoft.com/User.Read
https://graph.microsoft.com/Mail.Send
```

**Custom API:**
```
api://{api_application_id}/access_as_user
```

## Security Considerations

| Practice | Why |
|----------|-----|
| **Use state parameter** | Prevents CSRF attacks |
| **Use PKCE for public clients** | Prevents authorization code interception |
| **Validate tokens** | Verify signature, issuer, audience, expiration |
| **Use HTTPS only** | Protect tokens in transit |
| **Store tokens securely** | Use secure storage, never in localStorage for sensitive apps |
| **Implement token refresh** | Seamless UX without repeated logins |
| **Handle token expiration** | Gracefully refresh or re-authenticate |
| **Minimal scope principle** | Request only necessary permissions |

## Additional Resources

[OAuth 2.0 spec](https://www.rfc-editor.org/rfc/rfc6749)