> ## Documentation Index
> Fetch the complete documentation index at: https://docs-accounts.mubarokah.com/llms.txt
> Use this file to discover all available pages before exploring further.

# OAuth 2.0 Flows

> Detailed explanation of the OAuth 2.0 Authorization Code Grant and Refresh Token flows used by Mubarokah ID.

# OAuth 2.0 Flows

Mubarokah ID primarily uses the **OAuth 2.0 Authorization Code Grant** for third-party application authentication. This flow is designed for applications that can securely store a client secret. Additionally, a **Refresh Token Flow** is provided to obtain new access tokens without requiring user re-authentication.

## Authorization Code Grant (Recommended)

The Authorization Code Grant is the most common and secure OAuth 2.0 flow. It involves exchanging an authorization code for an access token.

```mermaid theme={null}
flowchart TD
    Start([Application Initiates OAuth]) --> Auth[Redirect to /oauth/authorize]
    
    subgraph "User Authentication"
        Auth --> LoggedIn{User Logged In?}
        LoggedIn -->|No| Login[Login at Mubarokah ID]
        LoggedIn -->|Yes| Consent[Review Permissions]
        Login --> Consent
    end
    
    subgraph "Authorization Decision"
        Consent --> UserDecision{Grant Consent?}
        UserDecision -->|Yes| AuthCode[Generate Authorization Code]
        UserDecision -->|No| Denied[Access Denied]
    end
    
    subgraph "Token Exchange"
        AuthCode --> Redirect[Redirect to App with Code]
        Redirect --> Exchange[Exchange Code for Tokens]
        Exchange --> Valid{Valid Credentials?}
        Valid -->|Yes| Tokens[Issue Access & Refresh Tokens]
        Valid -->|No| TokenError[Token Exchange Error]
    end
    
    subgraph "API Access"
        Tokens --> ApiCall[Call API with Access Token]
        ApiCall --> Success[User Session Established]
    end
    
    %% End states
    Denied --> End1([End: Access Denied])
    TokenError --> End2([End: Integration Error])
    Success --> End3([End: Authentication Complete])
    
    %% Styling
    classDef successPath fill:#d4edda,stroke:#155724,color:#155724
    classDef errorPath fill:#f8d7da,stroke:#721c24,color:#721c24
    classDef processPath fill:#e2e3e5,stroke:#383d41,color:#383d41
    
    class AuthCode,Tokens,ApiCall,Success,End3 successPath
    class Denied,TokenError,End1,End2 errorPath
    class Auth,Login,Consent,Redirect,Exchange processPath
```

### Detailed Step-by-Step Implementation

#### Step 1: Authorization Request (User Redirection)

Your application initiates the flow by redirecting the user's browser to Mubarokah ID's authorization endpoint.

```http theme={null}
GET /oauth/authorize HTTP/1.1
Host: accounts.mubarokah.com
```

**Parameters:**

| Parameter               | Type   | Required | Description                                                                       |
| ----------------------- | ------ | -------- | --------------------------------------------------------------------------------- |
| `response_type`         | string | ✅        | Must be `code`.                                                                   |
| `client_id`             | string | ✅        | Your application's unique Client ID.                                              |
| `redirect_uri`          | string | ✅        | The URL Mubarokah ID will redirect the user back to. Must match a registered URI. |
| `scope`                 | string | ❌        | Space-separated list of permissions (e.g., `view-user detail-user`).              |
| `state`                 | string | 🔸       | An opaque value used to prevent CSRF attacks. Highly recommended.                 |
| `prompt`                | string | ❌        | Optional. Set to `consent` to force the consent screen even if already approved.  |
| `code_challenge`        | string | ❌        | PKCE: The code challenge derived from the `code_verifier`. (Public clients)       |
| `code_challenge_method` | string | ❌        | PKCE: Usually `S256`. (Public clients)                                            |

**Example Redirect URL Construction (JavaScript):**

```javascript theme={null}
function generateRandomString(length = 40) {
  const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~';
  let result = '';
  const charactersLength = characters.length;
  for (let i = 0; i < length; i++) {
    result += characters.charAt(Math.floor(Math.random() * charactersLength));
  }
  return result;
}

const CLIENT_ID = "your_client_id";
const REDIRECT_URI = "https://yourapp.com/callback";

// Store state in session to verify later
const state = generateRandomString();
sessionStorage.setItem('oauth_state', state);

const authParams = {
  response_type: 'code',
  client_id: CLIENT_ID,
  redirect_uri: REDIRECT_URI,
  scope: 'view-user detail-user', // Request desired scopes
  state: state,
  // For PKCE (typically for mobile/SPA clients without a secure backend for token exchange)
  // code_challenge: 'generated_code_challenge',
  // code_challenge_method: 'S256'
};

const authorizationUrl = \`https://accounts.mubarokah.com/oauth/authorize?\${new URLSearchParams(authParams)}\`;
// Redirect the user
window.location.href = authorizationUrl;
```

#### Step 2: User Authentication & Consent

* The user is prompted to log in to Mubarokah ID (if not already).
* After successful login, Mubarokah ID displays a consent screen where the user can approve or deny the permissions (scopes) your application is requesting.

```mermaid theme={null}
flowchart TD
    A[User Clicks Login in Your App] --> B{User Authenticated with Mubarokah ID?}
    B -- No --> C[Mubarokah ID Login Page]
    C --> E[User Enters Credentials]
    E -- Valid --> D[Consent Screen: App requests permissions scopes]
    B -- Yes --> D

    D --> F{User Grants Consent?}
    F -- Yes --> G[Authorization Code Generated]
    F -- No --> H[Error: Access Denied]

    G --> I[Redirect to App's redirect_uri with 'code' and 'state']
    H --> J[Redirect to App's redirect_uri with 'error=access_denied']
```

#### Step 3: Authorization Code Response (Redirection to Your App)

If the user grants consent, Mubarokah ID redirects the user back to your application's `redirect_uri` with an `authorization_code` and the `state` parameter.

**Example Success Redirect:**

```text theme={null}
https://yourapp.com/callback?code=AUTHORIZATION_CODE_HERE&state=YOUR_ORIGINAL_STATE
```

<Info>
  Your application should first verify that the received `state` matches the one generated in Step 1 to prevent CSRF attacks.
</Info>

**Example Error Redirect:** If the user denies access or an error occurs:

```text theme={null}
https://yourapp.com/callback?error=access_denied&error_description=The+user+denied+access+to+your+application.&state=YOUR_ORIGINAL_STATE
```

#### Step 4: Token Exchange (Server-to-Server)

<Warning>
  This step **must** be performed on your application's backend server, as it requires your `client_secret`.
</Warning>

Your application exchanges the `authorization_code` for an `access_token` and a `refresh_token` by making a POST request to Mubarokah ID's token endpoint.

```http theme={null}
POST /oauth/token HTTP/1.1
Host: accounts.mubarokah.com
Content-Type: application/x-www-form-urlencoded
Authorization: Basic base64(client_id:client_secret) // Only if not sending client_id/secret in body
```

**`Request Body Parameters (application/x-www-form-urlencoded):`**

| Parameter       | Type   | Required | Description                                                                       |
| --------------- | ------ | -------- | --------------------------------------------------------------------------------- |
| `grant_type`    | string | ✅        | Must be `authorization_code`.                                                     |
| `code`          | string | ✅        | The authorization code received in Step 3.                                        |
| `redirect_uri`  | string | ✅        | The same `redirect_uri` used in Step 1.                                           |
| `client_id`     | string | ✅        | Your application's Client ID. (Required if not using Basic Auth header)           |
| `client_secret` | string | ✅        | Your application's Client Secret. (Required if not using Basic Auth header)       |
| `code_verifier` | string | ❌        | PKCE: The original `code_verifier` if `code_challenge` was used. (Public clients) |

**Example Token Exchange (Node.js - Server-Side):**

```javascript theme={null}
const fetch = require('node-fetch'); // Or your preferred HTTP client

const CLIENT_ID = "your_client_id";
const CLIENT_SECRET = "your_client_secret"; // Keep this secure on the server!
const REDIRECT_URI = "https://yourapp.com/callback";
const authorizationCode = "code_from_step_3";

async function exchangeCodeForTokens(code) {
  const params = new URLSearchParams();
  params.append('grant_type', 'authorization_code');
  params.append('code', code);
  params.append('redirect_uri', REDIRECT_URI);
  params.append('client_id', CLIENT_ID);
  params.append('client_secret', CLIENT_SECRET);
  // If using PKCE, also append:
  // params.append('code_verifier', stored_code_verifier);

  try {
    const response = await fetch('https://accounts.mubarokah.com/oauth/token', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        // Alternative to sending client_id/secret in body:
        // 'Authorization': 'Basic ' + Buffer.from(CLIENT_ID + ':' + CLIENT_SECRET).toString('base64')
      },
      body: params
    });

    const tokenData = await response.json();

    if (!response.ok) {
      throw new Error(tokenData.error_description || tokenData.error || 'Token exchange failed');
    }

    // Successfully received tokens:
    // tokenData.access_token
    // tokenData.refresh_token
    // tokenData.expires_in (lifetime of access token in seconds)
    // tokenData.token_type (usually "Bearer")
    // tokenData.scope (granted scopes)
    console.log(tokenData);
    return tokenData;
  } catch (error) {
    console.error('Token Exchange Error:', error.message);
    // Handle error appropriately
    throw error;
  }
}

// exchangeCodeForTokens(authorizationCode);
```

**Successful Token Response (JSON):**

```json theme={null}
{
  "token_type": "Bearer",
  "expires_in": 86400, // e.g., 24 hours
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9...",
  "refresh_token": "def502003e1b8f3c5f8b1a2d9e7f6c8d4e9b2a1c...",
  "scope": "view-user detail-user" // Granted scopes
}
```

Store the `access_token` and `refresh_token` securely, associating them with the user. The `access_token` is used to make API requests on behalf of the user.

## Refresh Token Flow

Access tokens are short-lived for security reasons. When an access token expires, your application can use a refresh token to obtain a new access token without requiring the user to go through the authorization flow again.

```http theme={null}
POST /oauth/token HTTP/1.1
Host: accounts.mubarokah.com
Content-Type: application/x-www-form-urlencoded
```

**`Request Body Parameters (application/x-www-form-urlencoded):`**

| Parameter       | Type   | Required | Description                                                                                 |
| --------------- | ------ | -------- | ------------------------------------------------------------------------------------------- |
| `grant_type`    | string | ✅        | Must be `refresh_token`.                                                                    |
| `refresh_token` | string | ✅        | The refresh token issued during the token exchange.                                         |
| `client_id`     | string | ✅        | Your application's Client ID.                                                               |
| `client_secret` | string | ✅        | Your application's Client Secret.                                                           |
| `scope`         | string | ❌        | Optional. Request a subset of the original scopes. If omitted, original scopes are granted. |

**Example Refresh Token Request (Node.js - Server-Side):**

```javascript theme={null}
const fetch = require('node-fetch');

const CLIENT_ID = "your_client_id";
const CLIENT_SECRET = "your_client_secret";
const existingRefreshToken = "user_refresh_token_here";

async function refreshAccessToken(refreshToken) {
  const params = new URLSearchParams();
  params.append('grant_type', 'refresh_token');
  params.append('refresh_token', refreshToken);
  params.append('client_id', CLIENT_ID);
  params.append('client_secret', CLIENT_SECRET);
  // params.append('scope', 'view-user'); // Optionally narrow scopes

  try {
    const response = await fetch('https://accounts.mubarokah.com/oauth/token', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
      },
      body: params
    });

    const tokenData = await response.json();

    if (!response.ok) {
      throw new Error(tokenData.error_description || tokenData.error || 'Token refresh failed');
    }

    // Successfully received new tokens:
    // tokenData.access_token
    // tokenData.refresh_token (sometimes a new refresh token is issued)
    // tokenData.expires_in
    // tokenData.token_type
    console.log("New Tokens:", tokenData);
    // Securely store the new tokens, potentially replacing the old refresh token if a new one is provided.
    return tokenData;
  } catch (error) {
    console.error('Token Refresh Error:', error.message);
    // If refresh fails (e.g., refresh token revoked or invalid),
    // the user may need to re-authenticate.
    throw error;
  }
}

// refreshAccessToken(existingRefreshToken);
```

<Info>
  Refresh tokens can also expire or be revoked. If the refresh token flow fails, your application should direct the user to re-initiate the Authorization Code Grant flow.
</Info>

## Client Credentials Grant (Machine-to-Machine)

For server-to-server communication where no user is directly involved, the Client Credentials Grant can be used. This flow allows your application to obtain an access token to access its own resources or act on its own behalf.

```http theme={null}
POST /oauth/token HTTP/1.1
Host: accounts.mubarokah.com
Content-Type: application/x-www-form-urlencoded
```

**`Request Body Parameters (application/x-www-form-urlencoded):`**

| Parameter       | Type   | Required | Description                                                             |
| --------------- | ------ | -------- | ----------------------------------------------------------------------- |
| `grant_type`    | string | ✅        | Must be `client_credentials`.                                           |
| `client_id`     | string | ✅        | Your application's Client ID.                                           |
| `client_secret` | string | ✅        | Your application's Client Secret.                                       |
| `scope`         | string | ❌        | Optional. Space-separated list of scopes relevant to client operations. |

**Example Client Credentials Request (Node.js - Server-Side):**

```javascript theme={null}
const fetch = require('node-fetch');

const CLIENT_ID = "your_client_id";
const CLIENT_SECRET = "your_client_secret";

async function getAppToken() {
  const params = new URLSearchParams();
  params.append('grant_type', 'client_credentials');
  params.append('client_id', CLIENT_ID);
  params.append('client_secret', CLIENT_SECRET);
  // params.append('scope', 'some-client-specific-scope'); // Optional

  try {
    const response = await fetch('https://accounts.mubarokah.com/oauth/token', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
      },
      body: params
    });

    const tokenData = await response.json();

    if (!response.ok) {
      throw new Error(tokenData.error_description || tokenData.error || 'Client credentials grant failed');
    }

    // Successfully received app access token:
    // tokenData.access_token
    // tokenData.expires_in
    // tokenData.token_type
    // tokenData.scope
    console.log("App Access Token:", tokenData.access_token);
    return tokenData;
  } catch (error) {
    console.error('Client Credentials Error:', error.message);
    throw error;
  }
}

// getAppToken();
```

This flow typically does not return a refresh token. When the access token expires, your application must request a new one using the same Client Credentials Grant.
