スキル一覧に戻る

oauth21-token-endpoint

maronnjapan / maronn-openid-provider

0🍴 0📅 2026年1月6日

OAuth 2.1 Token Endpoint implementation guide. Use when implementing token endpoint requirements beyond OpenID Connect, including grant types, token response format, Cache-Control headers, CORS support, and error handling. Covers OAuth 2.1 Section 3.2 and Section 4 requirements.

SKILL.md

---
name: oauth21-token-endpoint
description: OAuth 2.1 Token Endpoint implementation guide. Use when implementing token endpoint requirements beyond OpenID Connect, including grant types, token response format, Cache-Control headers, CORS support, and error handling. Covers OAuth 2.1 Section 3.2 and Section 4 requirements.
---

# OAuth 2.1 Token Endpoint

Token Endpoint requirements specific to OAuth 2.1 (beyond OpenID Connect).

## Endpoint Requirements

### HTTP Method

- MUST use POST method
- Other methods not allowed

### Content Type

- MUST accept `application/x-www-form-urlencoded`
- UTF-8 character encoding

### TLS

- MUST use HTTPS
- Except localhost for development

### CORS Support

For browser-based apps:
- Token endpoint MUST support CORS headers
- Return appropriate `Access-Control-Allow-Origin`

```http
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://client.example.com
Content-Type: application/json
```

## Supported Grant Types

### authorization_code

```http
POST /token HTTP/1.1
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=SplxlOBeZQQYbYS6WxSbIA
&code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
```

### refresh_token

```http
POST /token HTTP/1.1
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token
&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA
```

### client_credentials

```http
POST /token HTTP/1.1
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials
```

## Token Request Processing

### Client Authentication

```python
def process_token_request(request):
    # 1. Authenticate confidential clients
    if client.is_confidential:
        if not authenticate_client(request):
            return error_response("invalid_client")
    
    # 2. Validate grant type specific parameters
    # 3. Issue tokens
```

### Parameter Handling

- MUST ignore unrecognized parameters
- Parameters without value treated as omitted
- Parameters MUST NOT be included more than once

## Token Response

### Success Response

```http
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store

{
  "access_token": "2YotnFZFEjr1zCsicMWpAA",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "tGzv3JOkF0XG5Qx2TlKWIA",
  "scope": "openid profile"
}
```

### Required Fields

| Field | Description |
|-------|-------------|
| `access_token` | REQUIRED. The access token |
| `token_type` | REQUIRED. Type of token (e.g., "Bearer") |

### Optional Fields

| Field | Description |
|-------|-------------|
| `expires_in` | RECOMMENDED. Lifetime in seconds |
| `refresh_token` | OPTIONAL. Refresh token |
| `scope` | RECOMMENDED if same as request, REQUIRED if different |

### Token Type

- Value is case-insensitive
- `Bearer`, `bearer`, `BEARER` are all valid

## Required Headers

### Cache-Control

```http
Cache-Control: no-store
```

MUST include in any response containing tokens.

### Pragma (Legacy)

```http
Pragma: no-cache
```

May include for legacy HTTP/1.0 compatibility.

## Error Response

```http
HTTP/1.1 400 Bad Request
Content-Type: application/json

{
  "error": "invalid_grant",
  "error_description": "Authorization code expired",
  "error_uri": "https://example.com/docs/errors#invalid_grant"
}
```

### Error Codes

| Error | Description |
|-------|-------------|
| `invalid_request` | Missing/invalid parameter |
| `invalid_client` | Client authentication failed (401 status) |
| `invalid_grant` | Invalid grant (code, refresh_token, etc.) |
| `unauthorized_client` | Client not authorized for grant type |
| `unsupported_grant_type` | Grant type not supported |
| `invalid_scope` | Invalid/unknown scope |

### Error Field Character Restrictions

- `error`: %x20-21 / %x23-5B / %x5D-7E
- `error_description`: %x20-21 / %x23-5B / %x5D-7E
- `error_uri`: URI-reference syntax

## Authorization Code Grant Specifics

### Request Parameters

| Parameter | Requirement |
|-----------|-------------|
| `grant_type` | REQUIRED. Value: `authorization_code` |
| `code` | REQUIRED. The authorization code |
| `code_verifier` | REQUIRED if code_challenge was present |
| `client_id` | REQUIRED if not authenticating otherwise |

### Validation

1. Authenticate client if confidential
2. Verify code issued to this client
3. Verify code is valid and not expired
4. Verify code_verifier (see PKCE skill)
5. Return access token only once per code

### Code Reuse Handling

```python
def handle_code_reuse(code):
    if code.already_used:
        # MUST deny request
        # SHOULD revoke all tokens from this code
        revoke_tokens_for_code(code)
        return error_response("invalid_grant")
```

## Refresh Token Grant Specifics

### Request Parameters

| Parameter | Requirement |
|-----------|-------------|
| `grant_type` | REQUIRED. Value: `refresh_token` |
| `refresh_token` | REQUIRED. The refresh token |
| `scope` | OPTIONAL. Must not exceed original scope |

### Public Client Requirements

For public clients, refresh tokens MUST be either:
- Sender-constrained (bound to client proof)
- One-time use (rotation)

### Refresh Token Rotation

```python
def handle_refresh_token(refresh_token):
    # Issue new access token
    access_token = generate_access_token()
    
    # Optionally rotate refresh token
    if should_rotate:
        new_refresh_token = generate_refresh_token()
        invalidate(refresh_token)
        return {
            "access_token": access_token,
            "refresh_token": new_refresh_token
        }
    
    return {"access_token": access_token}
```

## Client Credentials Grant Specifics

### Request Parameters

| Parameter | Requirement |
|-----------|-------------|
| `grant_type` | REQUIRED. Value: `client_credentials` |
| `scope` | OPTIONAL |

### Requirements

- MUST only be used by confidential clients
- MUST authenticate client

## Removed from OAuth 2.1

These grant types are NOT in OAuth 2.1:

- **Implicit Grant** (`response_type=token`)
- **Resource Owner Password Credentials Grant**

## Implementation Checklist

1. [ ] Use POST method only
2. [ ] Accept application/x-www-form-urlencoded
3. [ ] Use HTTPS (except localhost)
4. [ ] Support CORS for browser apps
5. [ ] Include Cache-Control: no-store
6. [ ] Support authorization_code grant
7. [ ] Support refresh_token grant
8. [ ] Support client_credentials grant
9. [ ] Validate PKCE code_verifier
10. [ ] Enforce single-use authorization codes
11. [ ] Revoke tokens on code reuse
12. [ ] Handle refresh token rotation for public clients
13. [ ] Return proper error responses
14. [ ] Ignore unrecognized parameters