Skip to content
Back to skills

1205 Oauth Authorization Code Ui Design Ec055b8d

ASecurity

**Version**: 1.2 **Status**: Design + implementation notes **Date**: February 2026 **Related**: [OAuth Design Document](./oauth-design.md)

  • 9 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added June 1, 2026
securitysqlapidatabasebackendsecurity

Works with

  • cli
  • api
  • mcp

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned June 1, 2026

npx -y skills add tools-only/X-Skills --skill 1205-oauth-authorization-code-ui-design_ec055b8d --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 1205 Oauth Authorization Code Ui Design Ec055b8d?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 1205 Oauth Authorization Code Ui Design Ec055b8d
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-1205-oauth-authorization-code-ui-design-ec055b8d/badge)](https://www.skillsdirectory.com/skills/tools-only-1205-oauth-authorization-code-ui-design-ec055b8d)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
# OAuth 2.0 Authorization Code Flow UI Implementation Design

**Version**: 1.2
**Status**: Design + implementation notes
**Date**: February 2026
**Related**: [OAuth Design Document](./oauth-design.md)

## Executive Summary

This document describes how the Admin UI initiates OAuth 2.0 Authorization Code flow for MCP gateways and how the backend stores and uses user-delegated tokens. It reflects current behavior in code and calls out remaining gaps.

!!! note "Scope of This Document"
    This document covers the **UI implementation** for gateway OAuth token delegation - specifically how administrators configure OAuth settings and authorize access to upstream MCP servers.

    For information about **user authentication to ContextForge** (SSO, JWT tokens, RBAC), see:

    - [RBAC Configuration](../manage/rbac.md) - Token scoping, permissions, and access control
    - [Multi-Tenancy Architecture](./multitenancy.md) - User authentication flows and team management

## Current Implementation Snapshot

### Implemented today

- Admin UI exposes OAuth configuration fields for gateways and an "Authorize" action.
- Authorization Code flow uses PKCE (S256) and an HMAC-signed state value with a 300-second TTL.
- OAuth state is stored in Redis when `CACHE_TYPE=redis`, in the database when `CACHE_TYPE=database`, and in memory otherwise.
- Tokens are stored per gateway and app user (email) in `oauth_tokens`, encrypted with `AUTH_ENCRYPTION_SECRET`.
- Refresh tokens are used when access tokens are near expiry; invalid refresh tokens are cleared.
- DCR auto-registration can run during `/oauth/authorize/{gateway_id}` when `issuer` is set and `client_id` is missing.

### Known gaps and constraints

- `oauth_store_tokens` and `oauth_auto_refresh` checkboxes exist in the UI but are not persisted or enforced by the backend.
- `OAUTH_PREFERRED_CODE_CHALLENGE_METHOD` is defined but PKCE is always S256 today.
- No admin UI to list or revoke stored OAuth tokens per user.
- Token cleanup is a helper method only; there is no scheduler invoking it.

## Architecture Overview

```mermaid
graph TD
    subgraph "Admin UI"
        A[Gateway OAuth Configuration]
        B[Authorize Button]
    end

    subgraph "Backend"
        C[OAuth Router]
        D[OAuth Manager]
        E[Token Storage Service]
    end

    subgraph "State Store"
        S[Redis / Database / Memory]
    end

    subgraph "Database"
        G[gateways.oauth_config]
        T[oauth_tokens]
        ST[oauth_states when CACHE_TYPE=database]
    end

    subgraph "External"
        U[User Browser]
        O[OAuth Provider]
    end

    A --> G
    B --> C
    C --> D
    D --> S
    D --> O
    O --> C
    C --> E
    E --> T
    E --> ST
    B --> U
    U --> O
```

Authorize redirects to `/oauth/authorize/{gateway_id}`. The OAuth Manager performs PKCE and state handling.

## Data Model

### Gateway OAuth configuration (`gateways.oauth_config`)

Stored as JSON and assembled from Admin UI fields or API payloads.

- `grant_type`: `authorization_code`, `client_credentials`, or `password`
- `issuer`: OAuth Authorization Server issuer URL (required for DCR)
- `authorization_url`: OAuth authorization endpoint
- `token_url`: OAuth token endpoint
- `redirect_uri`: Must match the OAuth client registration
- `client_id`: OAuth client identifier
- `client_secret`: Encrypted before storage
- `username` / `password`: Used only for password grant
- `scopes`: Array of requested scopes
- `resource` (optional): RFC 8707 resource parameter; when omitted, `/oauth/authorize` derives it from the gateway URL

### `oauth_tokens`

One token record per gateway and app user (email).

- `gateway_id`, `app_user_email` (unique pair)
- `user_id` (OAuth provider user identifier)
- `access_token`, `refresh_token` (encrypted at rest)
- `token_type`, `expires_at`, `scopes`
- `created_at`, `updated_at`

### `oauth_states` (database-backed state storage)

Used only when `CACHE_TYPE=database`.

- `gateway_id`, `state` (unique)
- `code_verifier` (PKCE)
- `expires_at`, `used`, `created_at`
- TTL is enforced in logic (300 seconds)

### `registered_oauth_clients` (DCR, optional)

Stored when Dynamic Client Registration succeeds.

- `issuer`, `client_id`, `client_secret_encrypted`
- `redirect_uris`, `grant_types`, `response_types`, `scope`
- `token_endpoint_auth_method`, `registration_client_uri`
- `created_at`, `expires_at`, `is_active`

## UI and Flow

### Admin UI touchpoints

The gateway form maps these inputs into `oauth_config`:

- `oauth_grant_type`
- `oauth_issuer`
- `oauth_client_id`
- `oauth_client_secret`
- `oauth_authorization_url`
- `oauth_token_url`
- `oauth_redirect_uri`
- `oauth_scopes`
- `oauth_username` / `oauth_password` (password grant only)

The gateway list shows an **Authorize** button for OAuth gateways, which sends the current user through `/oauth/authorize/{gateway_id}`.

### Authorization Code flow (current)

```mermaid
sequenceDiagram
    participant Admin
    participant UI as Admin UI
    participant Gateway as OAuth Router (/oauth/authorize)
    participant OAuthMgr as OAuth Manager
    participant StateStore as State Store
    participant Provider as OAuth Provider
    participant TokenStore as Token Storage Service
    participant DB as Database

    Admin->>UI: Configure gateway OAuth settings
    UI->>DB: Save oauth_config in gateways

    Admin->>UI: Click "Authorize"
    UI->>Gateway: GET /oauth/authorize/{gateway_id}
    Gateway->>OAuthMgr: Initiate auth code flow (PKCE)
    OAuthMgr->>StateStore: Store state + code_verifier (TTL 300s)
    OAuthMgr-->>Gateway: Authorization URL
    Gateway-->>Admin: Redirect to provider

    Admin->>Provider: Login + consent
    Provider-->>Gateway: Redirect /oauth/callback?code&state
    Gateway->>OAuthMgr: Validate state + exchange code
    OAuthMgr->>Provider: POST /token (code + code_verifier)
    Provider-->>OAuthMgr: access_token + refresh_token
    OAuthMgr->>TokenStore: Store tokens for app_user_email
    TokenStore->>DB: Upsert oauth_tokens
    Gateway-->>Admin: Success page
```

### Tool invocation using stored tokens

```mermaid
sequenceDiagram
    participant Client as MCP Client (authenticated user)
    participant Gateway
    participant TokenStore as Token Storage Service
    participant Provider as OAuth Provider
    participant MCP as MCP Server

    Client->>Gateway: Invoke tool
    Gateway->>TokenStore: Get token for gateway + app_user_email
    TokenStore->>TokenStore: Check expiration

    alt Token valid
        TokenStore-->>Gateway: Decrypted access token
        Gateway->>MCP: Tool request + Bearer token
        MCP-->>Gateway: Tool response
        Gateway-->>Client: Result
    else Token expired
        TokenStore->>Provider: Refresh token request
        Provider-->>TokenStore: New access token
        TokenStore->>DB: Update oauth_tokens
        TokenStore-->>Gateway: New access token
        Gateway->>MCP: Tool request + Bearer token
        MCP-->>Gateway: Tool response
        Gateway-->>Client: Result
    end
```

## Security and Operational Notes

- Tokens are encrypted at rest using `AUTH_ENCRYPTION_SECRET` (via the encryption service).
- State is HMAC-signed with `AUTH_ENCRYPTION_SECRET`, single-use, and expires after 300 seconds.
- Tokens are scoped per gateway and app user (email); cross-user reuse is blocked.
- The gateway derives an RFC 8707 `resource` value from the gateway URL when `oauth_config.resource` is absent.
- HTTPS is recommended in production; the gateway does not enforce it automatically.

## Relationship to Gateway Authentication

This OAuth flow is for **upstream server authentication** and is separate from user authentication to ContextForge:

| Aspect | Gateway OAuth (this doc) | User Auth to Gateway |
|--------|-------------------------|---------------------|
| Purpose | Authenticate to upstream MCP servers | Authenticate users to the gateway |
| Initiated by | Admin UI "Authorize" button | Login flow (SSO, email, etc.) |
| Token storage | `oauth_tokens` table (encrypted) | JWT in client, session in browser |
| User involvement | User consents at OAuth provider | User authenticates to gateway |

For user authentication and RBAC configuration, see [RBAC Configuration](../manage/rbac.md).

## Configuration

| Setting | Default | Notes |
| --- | --- | --- |
| `OAUTH_REQUEST_TIMEOUT` | `30` | Timeout for OAuth HTTP requests |
| `OAUTH_MAX_RETRIES` | `3` | Retry count for token exchanges |
| `OAUTH_DEFAULT_TIMEOUT` | `3600` | Default `expires_in` when provider omits it |
| `AUTH_ENCRYPTION_SECRET` | `my-test-salt` | Encrypts OAuth tokens and signs state |
| `CACHE_TYPE` | `database` | `redis`, `database`, `memory`, or `none` |
| `REDIS_URL` | `redis://localhost:6379` | Required when `CACHE_TYPE=redis` |
| `DATABASE_URL` | `sqlite:///./mcp.db` | Required when `CACHE_TYPE=database` |
| `DCR_ENABLED` | `true` | Enable Dynamic Client Registration |
| `DCR_AUTO_REGISTER_ON_MISSING_CREDENTIALS` | `true` | Auto-register when issuer is set but client_id is missing |
| `DCR_DEFAULT_SCOPES` | `["mcp:read"]` | Default scopes for DCR |
| `DCR_ALLOWED_ISSUERS` | `[]` | Allowlist of issuer URLs |
| `DCR_TOKEN_ENDPOINT_AUTH_METHOD` | `client_secret_basic` | Token endpoint auth method |
| `DCR_METADATA_CACHE_TTL` | `3600` | Cache TTL for AS metadata discovery |
| `DCR_CLIENT_NAME_TEMPLATE` | `ContextForge ({gateway_name})` | DCR client_name template |
| `DCR_REQUEST_REFRESH_TOKEN_WHEN_UNSUPPORTED` | `false` | Request refresh token even if AS metadata omits support |
| `OAUTH_DISCOVERY_ENABLED` | `true` | Enable RFC 8414 discovery |
| `OAUTH_PREFERRED_CODE_CHALLENGE_METHOD` | `S256` | Defined but currently unused; PKCE is always S256 |

## Validation Checklist

- Create an OAuth gateway with `authorization_code` grant and complete provider consent via **Authorize**.
- Confirm an `oauth_tokens` record exists for your user and gateway.
- Invoke a tool to verify the stored token is used.
- Let the access token expire and confirm refresh happens when a refresh token is available.
- Switch `CACHE_TYPE` between `database` and `redis` to confirm state storage works in both modes.

## Future Enhancements

- Wire `oauth_store_tokens` and `oauth_auto_refresh` to backend behavior.
- Make PKCE method configurable using `OAUTH_PREFERRED_CODE_CHALLENGE_METHOD`.
- Add admin UI for token status and revocation.
- Schedule periodic cleanup of expired OAuth tokens.

Files in this skill

  • README.md992 B
  • skill.md10.2 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.