Files
stack/docs/scratchpads/86-authentik-oidc-integration.md
Jason Woltje dedc1af080
All checks were successful
ci/woodpecker/push/infra Pipeline was successful
ci/woodpecker/push/web Pipeline was successful
ci/woodpecker/push/api Pipeline was successful
fix(auth): restore BetterAuth OIDC flow across api/web/compose
2026-02-17 23:37:49 -06:00

7.2 KiB

Issue #86: [FED-003] Authentik OIDC Integration

Objective

Integrate Authentik OIDC authentication with the federation system to enable:

  • Federated authentication flows using Authentik as the identity provider
  • User identity mapping across federated instances
  • Token validation and verification for federated requests
  • Secure API endpoints for federated authentication

This builds on issues #84 (Instance Identity Model) and #85 (CONNECT/DISCONNECT Protocol).

Context

Existing Infrastructure

From issue #84:

  • Instance model with keypair for signing
  • FederationConnection model for managing connections
  • FederationService for instance identity management
  • CryptoService for encryption/decryption

From issue #85:

  • SignatureService for request signing/verification
  • ConnectionService for connection lifecycle management
  • Connection handshake protocol with status management

Current Authentication Setup

The project uses BetterAuth with Authentik OIDC provider:

  • /apps/api/src/auth/auth.config.ts - BetterAuth configuration with genericOAuth plugin
  • /apps/api/src/auth/auth.service.ts - Auth service with session verification
  • Environment variables: OIDC_ISSUER, OIDC_CLIENT_ID, OIDC_CLIENT_SECRET, OIDC_REDIRECT_URI

Requirements

Based on federation architecture and existing code patterns:

  1. Federation-Specific OIDC Provider: Create a dedicated OIDC provider configuration for federation that's separate from regular user authentication

  2. Cross-Instance Identity Linking: Map users authenticated via OIDC to their identity on federated instances

  3. Token Validation for Federation: Verify OIDC tokens in federated API requests

  4. Federated Authentication Endpoints: API endpoints for initiating and completing federated authentication flows

  5. Security: Ensure proper token validation, signature verification, and workspace isolation

Approach

1. Create Federation OIDC Types

Create /apps/api/src/federation/types/oidc.types.ts:

interface FederatedOIDCConfig {
  issuer: string;
  clientId: string;
  clientSecret: string;
  redirectUri: string;
  scopes: string[];
}

interface FederatedTokenValidation {
  valid: boolean;
  userId?: string;
  instanceId?: string;
  workspaceId?: string;
  error?: string;
}

interface FederatedIdentity {
  localUserId: string;
  remoteUserId: string;
  remoteInstanceId: string;
  oidcSubject: string;
  email: string;
  metadata: Record<string, unknown>;
}

2. Create OIDC Service for Federation

Create /apps/api/src/federation/oidc.service.ts:

  • configureFederatedProvider(instanceId, config) - Configure OIDC for remote instance
  • validateFederatedToken(token) - Validate OIDC token from federated request
  • linkFederatedIdentity(localUserId, remoteData) - Link local user to remote identity
  • getFederatedIdentity(localUserId, remoteInstanceId) - Retrieve identity mapping
  • revokeFederatedIdentity(localUserId, remoteInstanceId) - Remove identity link

3. Extend Prisma Schema

Add model for federated identity mapping:

model FederatedIdentity {
  id               String   @id @default(uuid()) @db.Uuid
  localUserId      String   @map("local_user_id") @db.Uuid
  remoteUserId     String   @map("remote_user_id")
  remoteInstanceId String   @map("remote_instance_id")
  oidcSubject      String   @map("oidc_subject")
  email            String
  metadata         Json     @default("{}")
  createdAt        DateTime @default(now()) @map("created_at") @db.Timestamptz
  updatedAt        DateTime @updatedAt @map("updated_at") @db.Timestamptz

  user User @relation(fields: [localUserId], references: [id], onDelete: Cascade)

  @@unique([localUserId, remoteInstanceId])
  @@index([localUserId])
  @@index([remoteInstanceId])
  @@index([oidcSubject])
  @@map("federated_identities")
}

4. Add Federation Auth Endpoints

Extend FederationController with:

  • POST /api/v1/federation/auth/initiate - Start federated auth flow
  • GET /api/v1/federation/auth/callback - Handle OIDC callback
  • POST /api/v1/federation/auth/validate - Validate federated token
  • GET /api/v1/federation/auth/identities - List user's federated identities
  • POST /api/v1/federation/auth/link - Link identity to remote instance
  • DELETE /api/v1/federation/auth/identities/:id - Revoke federated identity

5. Update Connection Service

Enhance ConnectionService to handle OIDC-based authentication:

  • Store OIDC configuration in connection metadata
  • Validate OIDC setup when accepting connections
  • Provide OIDC discovery endpoints to remote instances

6. Security Considerations

  • OIDC tokens must be validated using the issuer's public keys
  • Federated requests must include both OIDC token AND instance signature
  • Identity mapping must enforce workspace isolation
  • Token expiration must be respected
  • PKCE flow should be used for public clients
  • Refresh tokens should be stored securely (encrypted)

7. Testing Strategy

Unit Tests (TDD approach):

  • OIDCService.validateFederatedToken() validates tokens correctly
  • OIDCService.validateFederatedToken() rejects invalid tokens
  • OIDCService.linkFederatedIdentity() creates identity mapping
  • OIDCService.getFederatedIdentity() retrieves correct mapping
  • OIDCService.revokeFederatedIdentity() removes mapping
  • Workspace isolation for identity mappings

Integration Tests:

  • POST /auth/initiate starts OIDC flow with correct params
  • GET /auth/oauth2/callback/:providerId handles OIDC response and creates identity
  • POST /auth/validate validates tokens from federated instances
  • GET /auth/identities returns user's federated identities
  • Federated requests with valid tokens are authenticated
  • Invalid or expired tokens are rejected

Progress

  • Create scratchpad
  • Add FederatedIdentity model to Prisma schema
  • Generate migration
  • Create OIDC types
  • Write tests for OIDCService (14 tests)
  • Implement OIDCService
  • Write tests for federation auth endpoints (10 tests)
  • Implement auth endpoints in FederationAuthController
  • Update FederationModule
  • Update audit service with new logging methods
  • Verify all tests pass (24 OIDC tests, 94 total federation tests)
  • Verify type checking passes (no errors)
  • Verify test coverage (OIDCService: 79%, Controller: 100%)
  • Commit changes

Design Decisions

  1. Separate OIDC Configuration: Federation OIDC is separate from regular user auth to allow different IdPs per federated instance

  2. Identity Mapping Table: Explicit FederatedIdentity table rather than storing in connection metadata for better querying and RLS

  3. Dual Authentication: Federated requests require both OIDC token (user identity) AND instance signature (instance identity)

  4. Workspace Scoping: Identity mappings are user-scoped but authenticated within workspace context

  5. Token Storage: Store minimal token data; rely on OIDC provider for validation

Notes

  • Need to handle OIDC discovery for dynamic configuration
  • Should support multiple OIDC providers per instance (one per federated connection)
  • Consider token caching to reduce validation overhead
  • May need webhook for token revocation notifications
  • Future: Support for custom claims mapping