AgentSkillsCN

authentication

在设计认证与授权系统时使用——包括 OAuth 2.0 流程、JWT 处理、会话管理、RBAC/ABAC 模型、多租户模式,以及安全头配置。 适用场景:认证设计、授权模型、OAuth 2.0 流程、JWT 实现、会话管理、RBAC、ABAC、多租户模式、身份提供商选择、安全头、CORS 配置。 切勿用于:API 端点设计(使用 API 设计)、安全扫描/SAST(使用测试/静态分析)、基础设施安全(使用 IAC)。

SKILL.md
--- frontmatter
name: authentication
description: |
    Use when designing authentication and authorization systems — OAuth 2.0 flows, JWT handling, session management, RBAC/ABAC models, multi-tenancy patterns, and security header configuration.
    USE FOR: authentication design, authorization models, OAuth 2.0 flows, JWT implementation, session management, RBAC, ABAC, multi-tenancy patterns, identity provider selection, security headers, CORS configuration
    DO NOT USE FOR: API endpoint design (use api-design), security scanning/SAST (use testing/static-analysis), infrastructure security (use iac)
license: MIT
metadata:
  displayName: "Authentication & Authorization Patterns"
  author: "Tyler-R-Kendrick"
compatibility: claude, copilot, cursor

Authentication & Authorization Patterns

Overview

Authentication (authn) verifies who a user is. Authorization (authz) determines what they can do. Getting these right is non-negotiable -- a flaw in either can expose user data, enable privilege escalation, or bring regulatory consequences. This skill covers the major authentication flows, token formats, authorization models, multi-tenancy patterns, and security headers needed to build secure backend systems.

OAuth 2.0 Flows

Authorization Code + PKCE (Recommended for Most Apps)

The most secure flow for user-facing applications (SPAs, mobile apps, server-rendered apps). PKCE (Proof Key for Code Exchange) prevents authorization code interception attacks.

code
┌──────────┐                              ┌──────────────┐
│  Client   │──1. Auth request + ─────────>│ Authorization│
│  (Browser/│    code_challenge            │   Server     │
│   Mobile) │<──2. Redirect with ─────────│              │
│           │    authorization code        │              │
│           │──3. Exchange code + ─────────>│              │
│           │    code_verifier             │              │
│           │<──4. Access token + ─────────│              │
│           │    refresh token             │              │
└──────────┘                              └──────────────┘
       │                                         │
       │──5. API request with ──────────>┌──────────────┐
       │    Bearer access_token          │  Resource     │
       │<──6. Protected resource ────────│  Server       │
       │                                 └──────────────┘

Steps:

  1. Client generates a random code_verifier and derives code_challenge = SHA256(code_verifier).
  2. Client redirects user to authorization server with code_challenge.
  3. User authenticates and consents. Authorization server redirects back with an authorization code.
  4. Client exchanges the code + code_verifier for tokens. Server verifies SHA256(code_verifier) == code_challenge.
  5. Client uses the access token to call APIs.

Client Credentials (Machine-to-Machine)

For service-to-service communication where no user is involved.

code
Service A ──POST /token──> Authorization Server
            client_id +
            client_secret
            grant_type=client_credentials

Service A <──access_token── Authorization Server

Service A ──Bearer token──> Service B

Use when: Backend services authenticate to each other. No user context needed.

Device Code (TV / IoT / CLI)

For devices with limited input capability.

code
1. Device requests a device code and user code from auth server
2. Device displays: "Go to https://auth.example.com/device and enter code: ABCD-1234"
3. User visits URL on their phone/laptop, enters code, authenticates
4. Device polls auth server until user completes authentication
5. Auth server returns access token to device

OpenID Connect (OIDC)

OIDC is an identity layer built on top of OAuth 2.0. It adds:

ComponentPurpose
ID TokenA JWT containing user identity claims (sub, email, name) -- proves who the user is
UserInfo EndpointGET /userinfo returns additional user profile claims
DiscoveryGET /.well-known/openid-configuration returns all endpoint URLs, supported scopes, signing algorithms
Standard Scopesopenid (required), profile, email, address, phone

Key distinction: OAuth 2.0 alone is for authorization (access to resources). OIDC adds authentication (identity of the user).

JWT (JSON Web Token)

Structure

code
header.payload.signature

Header (base64url):
{
  "alg": "RS256",
  "typ": "JWT",
  "kid": "key-2024-01"
}

Payload (base64url):
{
  "iss": "https://auth.example.com",
  "sub": "user_42",
  "aud": "https://api.example.com",
  "exp": 1705312800,
  "iat": 1705309200,
  "scope": "read:orders write:orders",
  "roles": ["admin"],
  "tenant_id": "org_acme"
}

Signature:
  RS256(base64url(header) + "." + base64url(payload), private_key)

Standard Claims

ClaimPurpose
issIssuer -- who created the token
subSubject -- who the token represents
audAudience -- who the token is intended for
expExpiration time (Unix timestamp)
iatIssued at time
nbfNot before -- token is not valid before this time
jtiJWT ID -- unique identifier for the token

Access Tokens vs. Refresh Tokens

PropertyAccess TokenRefresh Token
PurposeAuthorize API requestsObtain new access tokens
LifetimeShort (5-60 minutes)Long (hours to days)
StoredMemory (preferred) or secure cookieSecure, HttpOnly cookie or secure storage
Sent toResource server (API)Authorization server only
RevocableDifficult (until expiry)Yes (server-side revocation list)

Token Rotation

Refresh token rotation issues a new refresh token with every access token refresh. If a refresh token is used twice, the server assumes the original was stolen and revokes the entire token family.

code
1. Client sends refresh_token_v1 → Server returns access_token + refresh_token_v2
2. Client sends refresh_token_v2 → Server returns access_token + refresh_token_v3
3. Attacker sends refresh_token_v1 → Server detects reuse → revokes ALL tokens for user

Session-Based Authentication

Server-Side Sessions

code
1. User submits credentials
2. Server validates, creates session record (in DB or Redis)
3. Server sends session ID in a cookie
4. Client sends cookie with every request
5. Server looks up session by ID, retrieves user context

Cookie Security

AttributePurposeRecommendation
HttpOnlyPrevents JavaScript access (XSS mitigation)Always set
SecureCookie sent only over HTTPSAlways set in production
SameSite=LaxMitigates CSRF for top-level navigationsDefault for most apps
SameSite=StrictCookie never sent cross-siteFor sensitive operations
Path=/Scope the cookie to a pathSet appropriately
Max-Age / ExpiresSession durationMatch your session TTL

CSRF Protection

  • SameSite cookies (Lax or Strict) -- primary defense in modern browsers.
  • Synchronizer Token Pattern -- server generates a random token, embeds in forms, validates on POST.
  • Double Submit Cookie -- CSRF token in both a cookie and a request header; server verifies they match.

API Key Authentication

Appropriate for:

  • Server-to-server communication where OAuth is overkill.
  • Public APIs with usage-based billing (keys identify the caller for rate limiting and billing).
  • Development/testing environments.

Not appropriate for: User-facing authentication (API keys cannot represent user identity or consent).

Best practices:

  • Treat API keys as secrets. Hash them in storage (like passwords).
  • Support key rotation: allow multiple active keys per client.
  • Include the key in a header (X-API-Key or Authorization: Bearer), never in the URL.
  • Scope keys to specific permissions and rate limits.

RBAC (Role-Based Access Control)

Users are assigned roles; roles are granted permissions. Users inherit the permissions of their assigned roles.

code
Role Hierarchy Example:

  admin
    ├── manage_users
    ├── manage_orders
    └── viewer (inherits)
          ├── read_orders
          └── read_products

User "Alice" → roles: [admin]
  → effective permissions: [manage_users, manage_orders, read_orders, read_products]

User "Bob" → roles: [viewer]
  → effective permissions: [read_orders, read_products]

Implementation Pattern

python
# Check permission, not role (more granular and maintainable)
# Bad:  if user.role == "admin"
# Good: if user.has_permission("manage_orders")

def require_permission(permission):
    def decorator(handler):
        def wrapper(request):
            if not request.user.has_permission(permission):
                raise ForbiddenError()
            return handler(request)
        return wrapper
    return decorator

@require_permission("manage_orders")
def cancel_order(request, order_id):
    ...

Best for: Most applications. Simple to understand, implement, and audit.

ABAC (Attribute-Based Access Control)

Access decisions based on attributes of the subject, resource, action, and environment -- evaluated by a policy engine.

Attribute SourceExamples
Subjectuser.role, user.department, user.clearance_level
Resourcedocument.classification, order.owner_id, record.tenant_id
Actionread, write, delete, approve
Environmentcurrent_time, ip_address, request.is_internal

Policy Example (Pseudocode)

code
PERMIT action=read ON resource=document
  WHERE subject.clearance_level >= resource.classification
    AND subject.department == resource.department
    AND environment.time BETWEEN 08:00 AND 18:00

Best for: Complex authorization requirements where RBAC role explosion becomes unmanageable (e.g., healthcare, government, multi-tenant SaaS with granular permissions).

Multi-Tenancy Patterns

PatternIsolation LevelComplexityCost
Shared database, shared schemaRow-level (tenant_id column)LowLowest
Shared database, schema-per-tenantSchema-levelMediumMedium
Database-per-tenantFull database isolationHighHighest

Row-Level Security (Shared Schema)

sql
-- PostgreSQL Row-Level Security
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;

CREATE POLICY tenant_isolation ON orders
  USING (tenant_id = current_setting('app.current_tenant')::uuid);

-- Set tenant context per request
SET app.current_tenant = 'org_acme';
SELECT * FROM orders;  -- only returns org_acme's orders

Decision heuristic:

  • Shared schema + RLS for most SaaS applications (simplest, cost-effective, sufficient isolation).
  • Schema-per-tenant when tenants need custom schema extensions or stronger isolation without separate databases.
  • Database-per-tenant when regulatory, compliance, or contractual requirements mandate full data isolation (e.g., healthcare, finance, government).

Identity Providers

ProviderTypeBest For
Auth0Managed (Okta)SaaS apps, rapid development, extensive social login support
Microsoft Entra ID (Azure AD)Managed (Microsoft)Enterprise apps, Microsoft ecosystem, B2B federation
Amazon CognitoManaged (AWS)AWS-native apps, user pools + federated identity
KeycloakOpen-source (self-hosted)Full control, on-premises, custom requirements
Firebase AuthManaged (Google)Mobile-first apps, Google ecosystem, quick prototyping

Recommendation: Use a managed identity provider unless you have strong requirements for self-hosting. Building authentication from scratch is a security liability.

Security Headers

HeaderPurposeRecommended Value
CORS (Access-Control-Allow-Origin)Controls which origins can call your APIExplicit allowlist (never * with credentials)
Content-Security-Policy (CSP)Controls what content the browser can load/executedefault-src 'self'; script-src 'self' (customize per app)
Strict-Transport-Security (HSTS)Forces HTTPS for all future requestsmax-age=31536000; includeSubDomains; preload
Referrer-PolicyControls how much referrer info is sentstrict-origin-when-cross-origin
X-Content-Type-OptionsPrevents MIME type sniffingnosniff
X-Frame-OptionsPrevents clickjacking via iframesDENY or SAMEORIGIN
Permissions-PolicyControls browser features (camera, mic, geolocation)Restrict to only what your app needs

CORS Configuration

code
# Preflight request
OPTIONS /api/orders
Origin: https://app.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Authorization, Content-Type

# Preflight response
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Authorization, Content-Type
Access-Control-Max-Age: 86400
Access-Control-Allow-Credentials: true

Rules:

  • Never use Access-Control-Allow-Origin: * when Access-Control-Allow-Credentials: true.
  • Maintain an explicit allowlist of trusted origins.
  • Set Access-Control-Max-Age to reduce preflight request overhead.

Best Practices

  • Use a managed identity provider (Auth0, Entra ID, Cognito, Keycloak) instead of building authentication from scratch. Authentication is a security-critical function where the cost of getting it wrong is severe.
  • Always use PKCE with the Authorization Code flow -- even for server-side apps. It adds security with no meaningful cost.
  • Keep access token lifetimes short (5-15 minutes). Use refresh tokens for longer sessions.
  • Check permissions, not roles, in your authorization code. This makes RBAC more granular and decouples business logic from role definitions.
  • Implement row-level security or tenant-scoped queries as a defense-in-depth measure -- never rely solely on application-level tenant filtering.
  • Set all security headers from day one. Adding HSTS, CSP, and CORS retroactively often breaks existing functionality.
  • Store secrets (API keys, client secrets, signing keys) in a secrets manager (AWS Secrets Manager, Azure Key Vault, HashiCorp Vault), never in code or environment variables in plain text.
  • Rotate signing keys and refresh tokens regularly. Implement token family revocation for refresh token reuse detection.