Files
2025-07-17 11:43:21 -07:00

8.5 KiB

Cognito Auth + Permit.io Authorization Design and Integration

Overview

This package uses AWS Cognito for authentication and Permit.io for dynamic authorization of API endpoints. The integration is tightly coupled with the Echo web framework and the OpenAPI (swagger) generated API code.

Key Components

1. Cognito Auth Package (internal/cognitoauth)

  • auth.go: Main exports for the package and middleware registration.
  • handler.go: HTTP handlers for login, callback, logout, and home.
  • middleware.go: Echo middleware for JWT extraction, validation, automatic token refresh, and Permit.io authorization enforcement.
  • jwks.go: Handles JWKS key fetching and JWT signature validation.
  • token.go: Token verification, expiration checking, and refresh token management.
  • models.go: Data models and types for tokens, users, etc.
  • permitio.go: Permit.io client integration and authorization logic.
  • mapping.go: Route-to-resource and HTTP method-to-action mapping.
  • validation.go: Startup validation for Permit.io configuration.
  • validation_unit_test.go: Unit tests for validation functions.

2. Service Config (internal/serviceconfig)

  • auth/config.go: Loads and manages authentication-related configuration and Permit.io settings.
  • common.go: Shared config logic.

3. API Layer (api/queryAPI)

  • api.gen.go: Swagger-generated API handlers.
  • authHandlers.go: Bridges generated code to Cognito logic; delegates to middleware for most flows.
  • homehandler.go: Displays authentication status.
  • controllers.go: Wires up controllers, but does not directly handle auth.

4. Server Setup (internal/server/api/listener.go)

  • Creates the Echo server.
  • Sets up config and logging middleware.
  • Sets up Prometheus and OpenAPI validation middleware.
  • Registers Cognito authentication middleware and routes before registering API handlers.
  • Validates Permit.io configuration at startup.

Cognito client user group setup

The cognito client must be setup to redirect back to /login-callback for PKCE flow to work.

Integration Flow

  1. Config Initialization: Auth config and Permit.io settings are loaded at startup.
  2. Startup Validation: ValidatePermitIOConfiguration() validates PDP connectivity and API key.
  3. Echo Server Setup: The Echo instance is created and set on the config.
  4. Auth Middleware Registration:
    • cognitoauth.RegisterRoutes(echoRouter, config) is called.
    • This registers login, callback, logout, and home endpoints.
    • It registers two middleware components: JWT extraction and token validation.
    • Authorization is enforced via Permit.io Policy Decision Point (PDP) queries.
  5. API Handler Registration:
    • OpenAPI-generated handlers are registered after the auth middleware.
    • All API endpoints are protected by the authentication and authorization middleware.
  6. Request Flow:
    • User requests a protected endpoint.
    • Middleware extracts JWT from cookies/headers and validates it.
    • Token Refresh: If token expires within 5 minutes, automatically refresh using stored refresh token.
    • Route is mapped to resource (first path segment) and HTTP method to action.
    • Permit.io PDP is queried: CheckPermission(user_subject, action, resource).
    • If authorized, the request proceeds to the handler.
    • If not, a JSON error response is returned (401/403).

Environment Configuration

# AWS Cognito Authentication
COGNITO_CLIENT_ID=your-client-id
COGNITO_CLIENT_SECRET=your-client-secret
COGNITO_USER_POOL_ID=your-pool-id
COGNITO_DOMAIN=https://your-domain.auth.region.amazoncognito.com
AWS_REGION=us-east-2

# Permit.io Authorization  
PERMIT_IO_API_KEY=permit_key_...
PERMIT_IO_PDP_URL=http://localhost:7766

# Feature Flags
DISABLE_AUTH=false
NO_JWT_VALIDATION=false  # Only for testing

Integration Example

// Validate Permit.io configuration at startup
if err := cognitoauth.ValidatePermitIOConfiguration(); err != nil {
    log.Fatal("Permit.io validation failed:", err)
}

// Register Cognito auth routes and middleware
cognitoauth.RegisterRoutes(echoRouter, config)

// Register API handlers (swagger-generated) 
RegisterHandlers(echoRouter, controllers)

Customization

  • Paths for login, callback, logout, and home can be configured.
  • Permit.io resources and actions are automatically mapped but can be customized.
  • Middleware can be extended or replaced for fine-grained control.
  • User info is accessible in handlers via helper functions.
  • Authorization policies are managed through Permit.io dashboard/API.

Authorization Flow

The system performs two-stage security enforcement:

  1. Authentication (AWS Cognito):

    • JWT token validation
    • User identity verification
    • Claims extraction (subject, groups, etc.)
  2. Authorization (Permit.io):

    • Route → Resource mapping (/document/123document)
    • HTTP Method → Action mapping (GETget)
    • PDP Query: CheckPermission(user_subject, action, resource)
    • Dynamic policy evaluation

Error Responses

Authentication Error (401):

{
  "error": "Authorization required",
  "message": "This endpoint requires authentication. Please obtain a valid JWT token.",
  "login_url": "/login"
}

Authorization Error (403):

{
  "error": "Insufficient permissions", 
  "message": "Access denied by authorization service",
  "user": "user-subject-id",
  "resource": "document",
  "action": "get"
}

Cognito Authentication Flow (mermaid)

For a live graph of the auto flow go here.

sequenceDiagram
    participant Browser
    participant AppServer as DoczyApiBE
    participant Cognito
    
    Browser->>AppServer: 1. GET /login
    Note over AppServer: 2. Generate code_verifier<br/>Generate code_challenge
    AppServer->>Browser: 3. Redirect to Cognito
    Browser->>Cognito: 4. GET /oauth2/authorize?...code_challenge
    Note over Cognito: 5. Process auth request
    Cognito->>Browser: 6. Cognito Login Page
    Browser->>Cognito: 7. User credentials
    Note over Cognito: 8. Validate credentials
    Cognito->>Browser: 9. Redirect with code
    Browser->>AppServer: 10. GET /login-callback?code=...
    Note over AppServer: 11. Retrieve code_verifier
    AppServer->>Cognito: 12. POST /oauth2/token<br/>code=...&code_verifier=...
    Note over Cognito: 13. Validate code and verifier
    Cognito->>AppServer: 14. Tokens response
    Note over AppServer: 15. Verify tokens<br/>Check permissions
    AppServer->>Browser: 16. Authentication successful

Token Refresh Flow

The system implements automatic token refresh to maintain seamless user sessions:

Token Storage Strategy

  • Access Token: Short-lived (1 hour), stored in auth_token cookie
  • Refresh Token: Long-lived (30 days), stored in refresh_token cookie
  • Security: Both cookies are HTTP-only and secure in production

Automatic Refresh Process

sequenceDiagram
    participant Browser
    participant Middleware as TokenValidationMiddleware
    participant Cognito
    
    Browser->>Middleware: 1. API Request with expired token
    Note over Middleware: 2. Check token expiration<br/>(5 min buffer)
    Middleware->>Middleware: 3. Extract refresh token from cookie
    Middleware->>Cognito: 4. POST /oauth2/token<br/>grant_type=refresh_token
    Cognito->>Middleware: 5. New tokens response
    Note over Middleware: 6. Update cookies with new tokens<br/>Set Authorization header
    Middleware->>Browser: 7. Process original request<br/>Return response with new cookies

Key Benefits

  • Transparent: Users never experience session interruptions
  • Proactive: Tokens refreshed 5 minutes before expiration
  • Secure: HTTP-only cookies prevent XSS attacks
  • Fallback: Graceful degradation to login when refresh fails