# EZLogin SSO System Integration Manual v5.0

This document explains how to integrate your application (Client) into the EZLogin SSO system to obtain user information via the standard OAuth 2.0 Authorization Code Flow.

**URL**: `https://login.24supports.com`
**API Version**: `v5`
**Document Version**: `5.0.0`
**Updated Date**: `2026-03-16`

---

## 📋 Table of Contents

1. [System Architecture and Flow](#1-system-architecture-and-flow)
2. [API Interface Description](#2-api-interface-description)
3. [Development Examples (PHP)](#3-development-examples-php)
4. [Security Recommendations](#4-security-recommendations)
5. [Frequently Asked Questions (FAQ)](#5-frequently-asked-questions-faq)
6. [Version Information](#6-version-information)
7. [Technical Support](#7-technical-support)
8. [Appendix](#8-appendix)

---

## 1. System Architecture and Flow

This system uses the standard **OAuth 2.0 Authorization Code Flow**, providing higher security:

```text
┌─────────┐                   ┌─────────┐                   ┌─────────┐
│  User   │                   │ Client  │                   │   SSO   │
│ Browser │                   │   App   │                   │ System  │
└────┬────┘                   └────┬────┘                   └────┬────┘
     │                              │                              │
     │  1. Click login button       │                              │
     ├─────────────────────────────>│                              │
     │                              │                              │
     │  2. Redirect to SSO + state  │                              │
     ├──────────────────────────────┼─────────────────────────────>│
     │                              │                              │
     │  3. Choose provider & login  │                              │
     │<─────────────────────────────┼──────────────────────────────┤
     │                              │                              │
     │  4. Callback + code + state  │                              │
     ├─────────────────────────────>│                              │
     │                              │                              │
     │                              │  5. Verify state             │
     │                              │     Exchange Token (Backend) │
     │                              ├─────────────────────────────>│
     │                              │                              │
     │                              │  6. Return access_token      │
     │                              │<─────────────────────────────┤
     │                              │                              │
     │                              │  7. Get user data (Backend)  │
     │                              ├─────────────────────────────>│
     │                              │                              │
     │                              │  8. Return user data         │
     │                              │<─────────────────────────────┤
     │                              │                              │
     │  9. Login success, session   │                              │
     │     created                  │                              │
     │<─────────────────────────────┤                              │
     │                              │                              │
```

### 1.1 Flow Description

1. **Initiate Login**: Client generates a random `state` and redirects the browser to the SSO system.
2. **User Authorization**: User logs in with a third-party provider (Google, LINE, etc.) on the SSO system.
3. **Authorization Callback**: SSO system redirects the user back to the Client's specified `redirect_uri` with authorization `code` and `state`.
4. **Verify State**: Client verifies if the returned `state` matches the one generated in step 1 (CSRF prevention).
5. **Exchange Token**: Client backend calls SSO API to exchange `code`, `client_id`, and `client_secret` for `access_token`.
6. **Fetch Data**: Client calls SSO API with the `access_token` to fetch detailed user information.

### 1.2 Supported Login Providers

| Provider | `provider` Parameter | Email Support | Note |
|----------|----------------------|---------------|------|
| Google | `google` | ✅ Returns directly | Most recommended |
| Microsoft | `microsoft` | ✅ Returns directly | Supports personal and enterprise accounts |
| LINE | `line` | ✅ Requires permission | Need to apply for email permission from LINE |

### 1.3 Unsupported Login Providers

| Provider | Reason |
|----------|--------|
| Facebook | Accounts are frequently blocked mistakenly; support temporarily suspended |
| X (Twitter) | Does not provide user email; unsupported |

> **⚠️ Note**: When using X (Twitter) login, user email cannot be obtained; only `sub` (user identifier) and `name` are available.

---

## 2. API Interface Description

### 2.1 Initiate Login Request (Browser Redirect)

Redirect the user to this URL to start the login flow.

**Endpoint Information**
- **URL**: `https://login.24supports.com/oauth/authorize`
- **Method**: `GET` (Browser Redirect)
- **Content-Type**: N/A (URL parameters)

**Request Parameters**

| Parameter | Required | Type | Description | Example |
|-----------|----------|------|-------------|---------|
| `provider` | ✅ Yes | string | Specify the login provider | `google`, `line`, `microsoft` |
| `client_id` | ✅ Yes | string | Your Client ID | `cli_xxxxxxxx` |
| `redirect_uri` | ✅ Yes | string | Callback URL (Must **exactly match** settings in backend) | `https://mysite.com/callback` |
| `state` | ✅ Yes | string | Random string used for CSRF protection | `xyz123random` |

**Example URL**
```text
https://login.24supports.com/oauth/authorize?provider=line&client_id=cli_12345&redirect_uri=https%3A%2F%2Fclient.com%2Fcallback&state=xyz123random
```

**Security Reminders**
- `state` must be generated using a cryptographically secure random number (at least 32 characters recommended).
- `redirect_uri` must use HTTPS (HTTP is allowed for local development).
- `redirect_uri` must strictly match the backend configuration, including the protocol, domain, and path.

---

### 2.2 Handling Callback

When login is successful, the browser will be redirected to your specific `redirect_uri` with the following parameters:

**Callback Parameters**

| Parameter | Type | Description |
|-----------|------|-------------|
| `code` | string | Short-lived authorization code (Valid for **60 seconds**, can only be used **once**) |
| `state` | string | The state parameter you sent in step 1. **Please verify it** |

**Callback Example**
```text
https://client.com/callback?code=def50200abc...xyz&state=xyz123random
```

**Error Callback**

If the login fails or is denied, the callback will contain error parameters:

```text
https://client.com/callback?error=access_denied&error_description=User+denied+access
```

---

### 2.3 Token Exchange (Token API)

Exchange the authorization `code` for an `access_token`.

**Endpoint Information**
- **URL**: `https://login.24supports.com/oauth/token`
- **Method**: `POST`
- **Content-Type**: `application/x-www-form-urlencoded`
- **Authentication**: No Authorization Header required
- **Rate Limit**: 30 requests per minute

**Request Parameters**

| Parameter | Required | Type | Description |
|-----------|----------|------|-------------|
| `grant_type` | ✅ Yes | string | Fixed value: `authorization_code` |
| `code` | ✅ Yes | string | The authorization code received in step 2.2 |
| `client_id` | ✅ Yes | string | Your Client ID |
| `client_secret` | ✅ Yes | string | Your Client Secret (**Please keep it secure**) |
| `redirect_uri` | ✅ Yes | string | Must exactly match the redirect_uri in step 2.1 |

**Request Example (cURL)**

```bash
curl -X POST https://login.24supports.com/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "code=def50200abc...xyz" \
  -d "client_id=cli_your_client_id" \
  -d "client_secret=your_client_secret" \
  -d "redirect_uri=https://yoursite.com/callback"
```

**Success Response - HTTP 200**

```json
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "expires_in": 3600
}
```

**Field Descriptions**
- `access_token`: Access token in JWT (HS256) format, used for subsequent API requests.
- `token_type`: Fixed as `Bearer`.
- `expires_in`: Token validity in seconds. Default is 3600 seconds (1 hour).

**Error Response - HTTP 400/401**

```json
{
  "error": "invalid_grant",
  "error_description": "Authorization code is invalid or expired"
}
```

**Common Error Codes**

| Error Code | Description |
|------------|-------------|
| `invalid_request` | Missing request parameters or format error |
| `invalid_grant` | Authorization code is invalid, used, or expired |
| `invalid_client` | Client ID or Secret is incorrect, or Client is disabled |
| `unsupported_grant_type` | Unsupported grant_type (only `authorization_code` is supported) |

---

### 2.4 Get User Information (UserInfo API)

Fetch current user details using the Access Token. This endpoint aligns with the OpenID Connect standard, directly returning data from JWT claims, which requires no database query and offers better performance.

**Endpoint Information**
- **URL**: `https://login.24supports.com/oauth/userinfo`
- **Method**: `GET`
- **Content-Type**: N/A
- **Authentication**: Bearer Token (Required)
- **Rate Limit**: 600 requests per minute

**Request Headers**

| Header | Required | Value |
|--------|----------|-------|
| `Authorization` | ✅ Yes | `Bearer <access_token>` |

**Request Example (cURL)**

```bash
curl -X GET https://login.24supports.com/oauth/userinfo \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
```

**Success Response - HTTP 200**

```json
{
  "sub": "line_u1234567890abcdef",
  "name": "Wang Xiaoming",
  "email": "ming@example.com",
  "provider": "line"
}
```

**Field Descriptions**

| Field | Type | Description | Nullable |
|-------|------|-------------|----------|
| `sub` | string | Unique user identifier (Format: `{provider}_{provider_user_id}`) | ❌ |
| `name` | string | User's display name | ❌ |
| `email` | string | User's email | ✅ (X/Twitter) |
| `provider` | string | Login provider (`google`, `line`, `microsoft`) | ❌ |

**Error Response - HTTP 401**

```json
{
  "type": "about:blank",
  "title": "Unauthorized",
  "status": 401,
  "detail": "Invalid or expired token",
  "instance": "/oauth/userinfo"
}
```

---

### 2.5 Token Introspection API (Introspect)

Check if an Access Token is valid, following the **RFC 7662 Token Introspection** standard.

**Endpoint Information**
- **URL**: `https://login.24supports.com/oauth/introspect`
- **Method**: `POST`
- **Content-Type**: `application/x-www-form-urlencoded`
- **Rate Limit**: 300 requests per minute

**Request Parameters**

| Parameter | Required | Type | Description |
|-----------|----------|------|-------------|
| `token` | ✅ Yes | string | The Access Token to inspect |

It can also be passed via the `Authorization: Bearer <token>` Header.

**Request Example (cURL)**

```bash
curl -X POST https://login.24supports.com/oauth/introspect \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
```

**Valid Token Response - HTTP 200**

```json
{
  "active": true,
  "sub": "line_u1234567890abcdef",
  "iss": "ezlogin",
  "client_id": "",
  "exp": 1711234567
}
```

**Invalid Token Response - HTTP 200**

```json
{
  "active": false
}
```

> **📌 Note**: According to RFC 7662, the HTTP status code is 200 regardless of whether the token is valid. Check the `active` field to determine token validity.

---

### 2.6 System Health Check (Health API)

Check if the SSO system is operating normally.

**Endpoint Information**
- **URL**: `https://login.24supports.com/healthz`
- **Method**: `GET`
- **Authentication**: None
- **Rate Limit**: 1000 requests per minute

**Request Example**

```bash
curl -X GET https://login.24supports.com/healthz
```

**Response - HTTP 200**

```json
{
  "status": "ok",
  "version": "3.0.0",
  "timestamp": "2026-03-16T10:00:00Z"
}
```

---

### 2.7 Rate Limiting

All API endpoints have rate limits based on fixed time window mechanisms for client IPs.

**Endpoint Limits**

| Endpoint | Limit |
|----------|-------|
| `/oauth/authorize` | 120 requests / minute |
| `/oauth/token` | 30 requests / minute |
| `/oauth/userinfo` | 600 requests / minute |
| `/oauth/introspect` | 300 requests / minute |
| `/healthz` | 1000 requests / minute |

**Response Headers**

Every API response will include the following rate limit information:

| Header | Description |
|--------|-------------|
| `X-RateLimit-Limit` | Maximum requests within the time window |
| `X-RateLimit-Remaining` | Remaining available requests |
| `X-RateLimit-Reset` | Unix timestamp when the limit resets |

**Exceed Limits Response - HTTP 429**

```json
{
  "success": false,
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Too many requests",
    "retry_after": 45
  }
}
```

---

## 3. Development Examples (PHP)

### 3.1 Login Page (login.php)

```php
<?php
// Session security configuration (must be set before session_start())
ini_set('session.cookie_httponly', 1);  // Prevent JavaScript from accessing Cookie
ini_set('session.cookie_secure', 1);    // Only transmit via HTTPS (Set to 0 for local development)
ini_set('session.cookie_samesite', 'Strict'); // Prevent CSRF
session_start();

// SSO Configuration
const SSO_URL = 'https://login.24supports.com';
const CLIENT_ID = 'cli_your_client_id';
const REDIRECT_URI = 'https://yoursite.com/callback.php';

// Generate a secure random state (32 characters)
$state = bin2hex(random_bytes(16));
$_SESSION['oauth_state'] = $state;

// Generate login URL (using Google)
$loginUrl = sprintf(
    '%s/oauth/authorize?provider=google&client_id=%s&redirect_uri=%s&state=%s',
    SSO_URL,
    CLIENT_ID,
    urlencode(REDIRECT_URI),
    $state
);
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Login - EZLogin SSO</title>
</head>
<body>
    <h1>Log in to your account</h1>

    <a href="<?= htmlspecialchars($loginUrl) ?>"
       style="display: inline-block; padding: 10px 20px; background: #4285f4; color: white; text-decoration: none; border-radius: 4px;">
        Login with Google
    </a>

    <!-- Other login options -->
    <?php
    $providers = [
        'line' => ['name' => 'LINE', 'color' => '#00b900'],
        'microsoft' => ['name' => 'Microsoft', 'color' => '#00a4ef'],
    ];

    foreach ($providers as $provider => $config) {
        $url = sprintf(
            '%s/oauth/authorize?provider=%s&client_id=%s&redirect_uri=%s&state=%s',
            SSO_URL,
            $provider,
            CLIENT_ID,
            urlencode(REDIRECT_URI),
            $state
        );
        printf(
            '<a href="%s" style="display: inline-block; padding: 10px 20px; background: %s; color: white; text-decoration: none; border-radius: 4px; margin-left: 10px;">Login with %s</a>',
            htmlspecialchars($url),
            $config['color'],
            $config['name']
        );
    }
    ?>
</body>
</html>
```

### 3.2 Callback Handling (callback.php)

```php
<?php
// Session security configuration
ini_set('session.cookie_httponly', 1);
ini_set('session.cookie_secure', 1);
ini_set('session.cookie_samesite', 'Strict');
session_start();

// SSO Configuration
const SSO_URL = 'https://login.24supports.com';
const CLIENT_ID = 'cli_your_client_id';
const CLIENT_SECRET = 'your_client_secret'; // ⚠️ Keep secure, DO NOT commit to version control
const REDIRECT_URI = 'https://yoursite.com/callback.php';

/**
 * Step 1: Verify State (CSRF prevention)
 */
$state = $_GET['state'] ?? '';
if (empty($_SESSION['oauth_state']) || !hash_equals($_SESSION['oauth_state'], $state)) {
    die('Error: Invalid state parameter (Potential CSRF attack)');
}

// Clear the used state
unset($_SESSION['oauth_state']);

/**
 * Step 2: Check for Errors
 */
if (isset($_GET['error'])) {
    $error = $_GET['error'];
    $errorDescription = $_GET['error_description'] ?? 'Unknown Error';
    die("Login Failed: {$error} - {$errorDescription}");
}

/**
 * Step 3: Get Authorization Code
 */
$code = $_GET['code'] ?? '';
if (!$code) {
    die('Error: Authorization code not received');
}

/**
 * Step 4: Exchange Access Token
 */
$tokenUrl = SSO_URL . '/oauth/token';
$tokenData = [
    'grant_type' => 'authorization_code',
    'code' => $code,
    'client_id' => CLIENT_ID,
    'client_secret' => CLIENT_SECRET,
    'redirect_uri' => REDIRECT_URI
];

$ch = curl_init($tokenUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($tokenData));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/x-www-form-urlencoded'
]);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

$data = json_decode($response, true);

if ($httpCode !== 200 || !isset($data['access_token'])) {
    $error = $data['error'] ?? 'unknown';
    $errorDesc = $data['error_description'] ?? 'Unknown error';
    die("Token exchange failed: {$error} - {$errorDesc}");
}

$accessToken = $data['access_token'];
$expiresIn = $data['expires_in'] ?? 3600;

/**
 * Step 5: Get User Data
 */
$userInfoUrl = SSO_URL . '/oauth/userinfo';

$ch = curl_init($userInfoUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer ' . $accessToken
]);

$userInfoResponse = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($httpCode !== 200) {
    die('Failed to get user data: HTTP ' . $httpCode);
}

$userInfo = json_decode($userInfoResponse, true);

/**
 * Step 6: Store Login State
 */
$_SESSION['user'] = [
    'login_id' => $userInfo['sub'],
    'name' => $userInfo['name'],
    'email' => $userInfo['email'] ?? null,
    'provider' => $userInfo['provider'],
    'logged_in_at' => time()
];

// Store Access Token (if needed for subsequent API calls)
$_SESSION['access_token'] = $accessToken;
$_SESSION['token_expires_at'] = time() + $expiresIn;

/**
 * Step 7: Redirect to Home Page or Dashboard
 */
header('Location: /dashboard.php');
exit;
```

### 3.3 Dashboard Page (dashboard.php)

```php
<?php
// Session security configuration
ini_set('session.cookie_httponly', 1);
ini_set('session.cookie_secure', 1);
ini_set('session.cookie_samesite', 'Strict');
session_start();

// Check login status
if (!isset($_SESSION['user'])) {
    header('Location: /login.php');
    exit;
}

$user = $_SESSION['user'];
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Dashboard</title>
</head>
<body>
    <h1>Welcome, <?= htmlspecialchars($user['name']) ?>!</h1>

    <ul>
        <li><strong>Login ID:</strong> <?= htmlspecialchars($user['login_id']) ?></li>
        <li><strong>Email:</strong> <?= htmlspecialchars($user['email'] ?? '(Not Provided)') ?></li>
        <li><strong>Login Provider:</strong> <?= htmlspecialchars($user['provider']) ?></li>
        <li><strong>Logged in at:</strong> <?= date('Y-m-d H:i:s', $user['logged_in_at']) ?></li>
    </ul>

    <a href="/logout.php">Logout</a>
</body>
</html>
```

### 3.4 Logout Handling (logout.php)

```php
<?php
// Session security configuration
ini_set('session.cookie_httponly', 1);
ini_set('session.cookie_secure', 1);
ini_set('session.cookie_samesite', 'Strict');
session_start();
session_destroy();
header('Location: /login.php');
exit;
```

---

## 4. Security Recommendations

### 4.1 Client Secret Protection

- ⚠️ **Absolutely do not** expose the Client Secret in frontend code, JavaScript, or version control systems.
- ✅ Client Secret must only be used on backend servers.
- ✅ Store using environment variables or encrypted configuration files.
- ✅ Rotate the Client Secret periodically.

### 4.2 State Verification

- ✅ You must implement state verification to prevent CSRF attacks.
- ✅ State must be generated using a cryptographically secure random number (e.g., 32+ characters).
- ✅ State should be stored in Session and cleared immediately after verification.
- ✅ Use `hash_equals()` for time-safe string comparisons.

### 4.3 Mandatory HTTPS

- ✅ HTTPS must be used throughout the process to encrypt transmission.
- ⚠️ HTTP can be used for local development, but HTTPS must be used in production.
- ✅ Ensure that the `redirect_uri` uses HTTPS.

### 4.4 Redirect URI Restrictions

- ✅ Must strictly match the `redirect_uri` set in the backend.
- ⚠️ Wildcards or loose matching are not allowed.
- ✅ Protocol, domain, port, and path must match identically.

### 4.5 Token Security

- ✅ Access Tokens should be stored in the backend Session and not exposed to the frontend.
- ✅ If the frontend needs the token, use an HttpOnly Cookie.
- ✅ Implement token expiration checks.
- ⚠️ Rotate the Client Secret immediately if a token is compromised.

### 4.6 Authorization Code Protection

- ⚠️ The authorization code (`code`) is valid for only 60 seconds.
- ⚠️ The authorization code can only be used once.
- ✅ Exchange for the token immediately after receiving the authorization code.

---

## 5. Frequently Asked Questions (FAQ)

### Q1: Can the old Implicit Flow (returning Token directly) still be used?

**A:** No. The system only supports Authorization Code Flow. Returning the token directly via URL is not supported for security reasons.

### Q2: How long is the Access Token valid?

**A:** Default validity is **1 hour (3600 seconds)**. Users need to log in again after the token expires.

### Q3: How to obtain or reset the Client Secret?

**A:** Please contact the system administrator or reset it in the backend management interface. Upon reset, the old Secret will become invalid immediately.

### Q4: Why does my redirect_uri always fail?

**A:** Common reasons:
- ❌ Inconsistent protocol (http vs https).
- ❌ Inconsistent path (e.g., missing/extra trailing slash).
- ❌ Inconsistent port (`:80` vs empty).
- ❌ Not configured correctly in the backend.

**Solution:** Ensure your `redirect_uri` exactly matches what is configured in the backend, including protocol, domain, port, and path.

### Q5: Can the Token API be called directly from the frontend?

**A:** **Absolutely not**. The Token API requires a Client Secret. Calling it from the frontend will leak the key. It must be called from your backend server.

### Q6: Can the authorization code (`code`) be reused?

**A:** No. The authorization code can only be used **once**, and is valid for only **60 seconds**. It becomes invalid immediately after use.

### Q7: How to handle X (Twitter) logins that do not return an email?

**A:** Recommended approach:
1. Use `sub` as the unique user identifier.
2. If your system requires an email, prompt the user to provide it.
3. Or guide the user to use other login methods (e.g., Google, LINE).

### Q8: What are the Rate Limit limits?

**A:**
- Authorize: 120 req/min
- Token API: 30 req/min
- UserInfo API: 600 req/min
- Introspect API: 300 req/min
- Exceeding the limits will return an `HTTP 429 Too Many Requests` response along with `X-RateLimit-*` Headers.

### Q9: Are Refresh Tokens supported?

**A:** Currently, Refresh Tokens are not supported. Users must re-authorize after the token expires.

### Q10: How to test the integration?

**A:** Recommended steps:
1. Use the Health API (`/healthz`) first to confirm the system operates normally.
2. Test the complete flow in a local environment.
3. Monitor network requests using browser developer tools.
4. Verify if `state` verification is properly implemented.
5. Check HTTPS settings (production).

### Q11: Does the UserInfo response include a profile picture?

**A:** No. The UserInfo endpoint returns data directly from JWT claims and does not include profile pictures. If needed, fetch it from the respective third-party provider's API.

---

## 6. Version Information

### Update History

| Version | Date | Update Details |
|---------|------|----------------|
| **5.0.0** | 2026-03-16 | • Rewritten completely in Go backend (High Performance)<br>• OAuth endpoints consolidated under `/oauth/*` path<br>• Standardized parameter names: `provider`, `client_id`<br>• UserInfo follows OIDC standard (`sub` identifier)<br>• Added RFC 7662 Token Introspect endpoint<br>• Added fine-grained rate limits with `X-RateLimit-*` Headers<br>• Error formatting complies with RFC 9457 Problem Details<br>• Health check endpoint `/healthz` |

---

## 7. Technical Support

### Contact Information

- **Document URL**: https://login.24supports.com/doc/
- **Issue Reporting**: Contact the system administrator
- **Emergency Support**: service@gceit.com

### Related Resources

- [OAuth 2.0 RFC 6749](https://tools.ietf.org/html/rfc6749)
- [JWT Specification RFC 7519](https://tools.ietf.org/html/rfc7519)
- [Token Introspection RFC 7662](https://tools.ietf.org/html/rfc7662)
- [Problem Details RFC 9457](https://tools.ietf.org/html/rfc9457)
- [OWASP Authentication Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html)

---

## 8. Appendix

### 8.1 Complete Error Code List

| HTTP Status Code | Error Code | Description | Solution |
|------------------|------------|-------------|----------|
| 400 | `invalid_request` | Request parameters missing or invalid format | Check required parameters |
| 400 | `invalid_grant` | Authorization code invalid, used, or expired | Re-fetch authorization code |
| 400 | `unsupported_grant_type` | Unsupported grant_type | Use `authorization_code` |
| 401 | `invalid_client` | Client ID or Secret incorrect | Check credentials |
| 401 | `invalid_token` | Access Token invalid or expired | Re-fetch Token |
| 403 | `access_denied` | User refused authorization | Guide user to authorize |
| 404 | `not_found` | API endpoint does not exist | Check URL spelling |
| 429 | `RATE_LIMIT_EXCEEDED` | Exceeded rate limit | Retry after `retry_after` |
| 500 | `server_error` | Internal server error | Contact technical support |

### 8.2 State Generation Examples

**PHP**
```php
$state = bin2hex(random_bytes(32)); // 64 characters
```

**JavaScript (Node.js)**
```javascript
const crypto = require('crypto');
const state = crypto.randomBytes(32).toString('hex'); // 64 characters
```

**Python**
```python
import secrets
state = secrets.token_hex(32)  # 64 characters
```

**Go**
```go
import "crypto/rand"
import "encoding/hex"

b := make([]byte, 32)
rand.Read(b)
state := hex.EncodeToString(b) // 64 characters
```

---

**End of Document**

*Last Updated: 2026-03-16*
*Version: 5.0.0*
*Author: EZLogin SSO Development Team*
