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:
-
Federation-Specific OIDC Provider: Create a dedicated OIDC provider configuration for federation that's separate from regular user authentication
-
Cross-Instance Identity Linking: Map users authenticated via OIDC to their identity on federated instances
-
Token Validation for Federation: Verify OIDC tokens in federated API requests
-
Federated Authentication Endpoints: API endpoints for initiating and completing federated authentication flows
-
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 instancevalidateFederatedToken(token)- Validate OIDC token from federated requestlinkFederatedIdentity(localUserId, remoteData)- Link local user to remote identitygetFederatedIdentity(localUserId, remoteInstanceId)- Retrieve identity mappingrevokeFederatedIdentity(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 flowGET /api/v1/federation/auth/callback- Handle OIDC callbackPOST /api/v1/federation/auth/validate- Validate federated tokenGET /api/v1/federation/auth/identities- List user's federated identitiesPOST /api/v1/federation/auth/link- Link identity to remote instanceDELETE /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
-
Separate OIDC Configuration: Federation OIDC is separate from regular user auth to allow different IdPs per federated instance
-
Identity Mapping Table: Explicit FederatedIdentity table rather than storing in connection metadata for better querying and RLS
-
Dual Authentication: Federated requests require both OIDC token (user identity) AND instance signature (instance identity)
-
Workspace Scoping: Identity mappings are user-scoped but authenticated within workspace context
-
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