- Add TypeScript interfaces for multi-provider OAuth2 support - Create OAuth2ClientWithConfig extending arctic OAuth2Client with OIDC discovery - Create OAuth2ProviderFactory with strategy pattern for different providers - Create OAuth2ProviderManager for managing multiple providers with health checks - Support for OBP-OIDC, Keycloak, Google, GitHub, and custom providers
9.6 KiB
Multi-OIDC Provider Implementation - Executive Summary
Overview
This document provides a high-level summary of implementing multiple OIDC provider support in API Explorer II, based on the proven architecture from OBP-Portal.
Current State
API Explorer II currently supports OAuth2/OIDC authentication with a single provider configured via environment variables:
VITE_OBP_OAUTH2_WELL_KNOWN_URL=http://localhost:9000/obp-oidc/.well-known/openid-configuration
VITE_OBP_OAUTH2_CLIENT_ID=<client-id>
VITE_OBP_OAUTH2_CLIENT_SECRET=<client-secret>
Limitations:
- Only one OIDC provider supported at a time
- No user choice of authentication method
- Requires redeployment to switch providers
- No fallback if provider is unavailable
Target State
Multi-Provider Support allows users to choose from multiple identity providers at login:
- OBP-OIDC - Open Bank Project's identity provider
- Keycloak - Enterprise identity management
- Google - Consumer identity (optional)
- GitHub - Developer identity (optional)
- Custom - Any OpenID Connect provider
How OBP-Portal Does It
1. Dynamic Provider Discovery
OBP-Portal fetches available OIDC providers from the OBP API:
GET /obp/v5.1.0/well-known
Response:
{
"well_known_uris": [
{
"provider": "obp-oidc",
"url": "http://localhost:9000/obp-oidc/.well-known/openid-configuration"
},
{
"provider": "keycloak",
"url": "http://localhost:8180/realms/obp/.well-known/openid-configuration"
}
]
}
2. Provider Manager
Key Component: OAuth2ProviderManager
Responsibilities:
- Fetch well-known URIs from OBP API
- Initialize OAuth2 client for each provider
- Track provider health (available/unavailable)
- Perform periodic health checks (60s intervals)
- Provide access to specific providers
3. Provider Factory
Key Component: OAuth2ProviderFactory
Responsibilities:
- Strategy pattern for provider-specific configuration
- Load credentials from environment variables
- Create OAuth2 clients with OIDC discovery
- Support multiple provider types
Strategy Pattern:
strategies.set('obp-oidc', {
clientId: process.env.VITE_OBP_OAUTH2_CLIENT_ID,
clientSecret: process.env.VITE_OBP_OAUTH2_CLIENT_SECRET,
redirectUri: process.env.VITE_OBP_OAUTH2_REDIRECT_URL
})
strategies.set('keycloak', {
clientId: process.env.VITE_KEYCLOAK_CLIENT_ID,
clientSecret: process.env.VITE_KEYCLOAK_CLIENT_SECRET,
redirectUri: process.env.VITE_KEYCLOAK_REDIRECT_URL
})
4. User Flow
1. User clicks "Login"
→ Shows provider selection dialog
2. User selects provider (e.g., "OBP-OIDC")
→ GET /api/oauth2/connect?provider=obp-oidc
3. Server:
- Retrieves OAuth2 client for "obp-oidc"
- Generates PKCE parameters
- Stores provider name in session
- Redirects to provider's authorization endpoint
4. User authenticates on selected OIDC provider
5. Provider redirects back:
→ GET /api/oauth2/callback?code=xxx&state=yyy
6. Server:
- Retrieves provider from session ("obp-oidc")
- Gets corresponding OAuth2 client
- Exchanges code for tokens
- Stores tokens with provider name
7. User authenticated with selected provider
Implementation Architecture for API Explorer II
New Services
1. OAuth2ClientWithConfig (extends OAuth2Client from arctic)
class OAuth2ClientWithConfig extends OAuth2Client {
public OIDCConfig?: OIDCConfiguration
public provider: string
async initOIDCConfig(oidcConfigUrl: string): Promise<void>
getAuthorizationEndpoint(): string
getTokenEndpoint(): string
getUserInfoEndpoint(): string
}
2. OAuth2ProviderFactory
class OAuth2ProviderFactory {
private strategies: Map<string, ProviderStrategy>
async initializeProvider(wellKnownUri: WellKnownUri): Promise<OAuth2ClientWithConfig>
getConfiguredProviders(): string[]
}
3. OAuth2ProviderManager
class OAuth2ProviderManager {
private providers: Map<string, OAuth2ClientWithConfig>
async fetchWellKnownUris(): Promise<WellKnownUri[]>
async initializeProviders(): Promise<boolean>
getProvider(providerName: string): OAuth2ClientWithConfig
getAvailableProviders(): string[]
startHealthCheck(intervalMs: number): void
}
Updated Controllers
1. OAuth2ProvidersController (NEW)
GET /api/oauth2/providers
→ Returns: { providers: [...], count: 2, availableCount: 1 }
2. OAuth2ConnectController (UPDATED)
GET /api/oauth2/connect?provider=obp-oidc&redirect=/resource-docs
→ Redirects to selected provider's authorization endpoint
3. OAuth2CallbackController (UPDATED)
GET /api/oauth2/callback?code=xxx&state=yyy
→ Uses provider from session to exchange code for tokens
Frontend Updates
HeaderNav.vue (UPDATED)
Before:
<a href="/api/oauth2/connect">Login</a>
After:
<button @click="handleLoginClick">
Login
<span v-if="availableProviders.length > 1">▼</span>
</button>
<!-- Provider Selection Dialog -->
<el-dialog v-model="showProviderSelector">
<div v-for="provider in availableProviders">
<div @click="loginWithProvider(provider.name)">
{{ provider.name }}
</div>
</div>
</el-dialog>
Configuration
Environment Variables
# OBP-OIDC Provider
VITE_OBP_OAUTH2_CLIENT_ID=48ac28e9-9ee3-47fd-8448-69a62764b779
VITE_OBP_OAUTH2_CLIENT_SECRET=fOTQF7jfg8C74u7ZhSjVQpoBYvD0KpWfM5UsEZBSFFM
VITE_OBP_OAUTH2_REDIRECT_URL=http://localhost:5173/api/oauth2/callback
# Keycloak Provider
VITE_KEYCLOAK_CLIENT_ID=obp-api-explorer
VITE_KEYCLOAK_CLIENT_SECRET=your-keycloak-secret
VITE_KEYCLOAK_REDIRECT_URL=http://localhost:5173/api/oauth2/callback
# Google Provider (Optional)
VITE_GOOGLE_CLIENT_ID=your-google-client-id
VITE_GOOGLE_CLIENT_SECRET=your-google-client-secret
VITE_GOOGLE_REDIRECT_URL=http://localhost:5173/api/oauth2/callback
Note: No need to specify well-known URLs - they are fetched from OBP API!
Key Benefits
1. Dynamic Discovery
- Providers are discovered from OBP API at runtime
- No hardcoded provider list
- Easy to add new providers without code changes
2. User Choice
- Users select their preferred authentication method
- Better user experience
- Support for organizational identity preferences
3. Resilience
- Health monitoring detects provider outages
- Can fallback to alternative providers
- Automatic retry for failed initializations
4. Extensibility
- Strategy pattern makes adding providers trivial
- Just add environment variables
- No code changes needed
5. Backward Compatibility
- Existing single-provider mode still works
- Gradual migration path
- No breaking changes
Implementation Phases
Phase 1: Backend Services (Week 1)
- Create
OAuth2ClientWithConfig - Create
OAuth2ProviderFactory - Create
OAuth2ProviderManager - Create TypeScript interfaces
Phase 2: Backend Controllers (Week 1-2)
- Create
OAuth2ProvidersController - Update
OAuth2ConnectControllerwith provider parameter - Update
OAuth2CallbackControllerto use provider from session
Phase 3: Frontend (Week 2)
- Update
HeaderNav.vueto fetch providers - Add provider selection UI (dialog/dropdown)
- Update login flow to include provider selection
Phase 4: Configuration & Testing (Week 2-3)
- Configure environment variables for multiple providers
- Write unit tests
- Write integration tests
- Manual testing with OBP-OIDC and Keycloak
- Update documentation
Migration Path
Step 1: Deploy with Backward Compatibility
- Implement new services
- Keep existing single-provider mode working
- Test thoroughly
Step 2: Enable Multi-Provider
- Add provider environment variables
- Enable provider selection UI
- Monitor for issues
Step 3: Deprecate Single-Provider
- Update documentation
- Remove
VITE_OBP_OAUTH2_WELL_KNOWN_URLenv variable - Use OBP API well-known endpoint by default
Testing Strategy
Unit Tests
OAuth2ProviderFactory.test.ts- Strategy creationOAuth2ProviderManager.test.ts- Provider initializationOAuth2ClientWithConfig.test.ts- OIDC config loading
Integration Tests
- Multi-provider login flow
- Provider selection
- Token exchange with different providers
- Callback handling
Manual Testing
- Login with OBP-OIDC
- Login with Keycloak
- Provider unavailable scenarios
- Network error handling
- User cancellation
Success Criteria
- ✅ Users can choose from multiple OIDC providers
- ✅ Providers are discovered from OBP API automatically
- ✅ Health monitoring detects provider outages
- ✅ Backward compatible with single-provider mode
- ✅ No code changes needed to add new providers (only env vars)
- ✅ Comprehensive test coverage (>80%)
- ✅ Documentation updated
References
- Full Implementation Guide:
MULTI-OIDC-PROVIDER-IMPLEMENTATION.md - OBP-Portal Reference:
~/Documents/workspace_2024/OBP-Portal - OBP API Well-Known Endpoint:
/obp/v5.1.0/well-known - Current OAuth2 Docs:
OAUTH2-README.md,OAUTH2-OIDC-INTEGRATION-PREP.md - Arctic OAuth2 Library: https://github.com/pilcrowOnPaper/arctic
- OpenID Connect Discovery: https://openid.net/specs/openid-connect-discovery-1_0.html
Questions?
For detailed implementation instructions, see MULTI-OIDC-PROVIDER-IMPLEMENTATION.md
For OBP-Portal reference implementation, see:
OBP-Portal/src/lib/oauth/providerManager.tsOBP-Portal/src/lib/oauth/providerFactory.tsOBP-Portal/src/lib/oauth/client.ts