Add OIDC provider functionality with validation setup

This commit adds OpenID Connect (OIDC) provider functionality to tinyauth,
allowing it to act as an OIDC identity provider for other applications.

Features:
- OIDC discovery endpoint at /.well-known/openid-configuration
- Authorization endpoint for OAuth 2.0 authorization code flow
- Token endpoint for exchanging authorization codes for tokens
- ID token generation with JWT signing
- JWKS endpoint for public key distribution
- Support for PKCE (code challenge/verifier)
- Nonce validation for ID tokens
- Configurable OIDC clients with redirect URIs, scopes, and grant types

Validation:
- Docker Compose setup for local testing
- OIDC test client (oidc-whoami) with session management
- Nginx reverse proxy configuration
- DNS server (dnsmasq) for custom domain resolution
- Chrome launch script for easy testing

Configuration:
- OIDC configuration in config.yaml
- Example configuration in config.example.yaml
- Database migrations for OIDC client storage
This commit is contained in:
Olivier Dumont
2025-12-30 12:17:40 +01:00
parent 986ac88e14
commit 020fcb9878
21 changed files with 1873 additions and 8 deletions

View File

@@ -102,5 +102,15 @@ func (app *BootstrapApp) setupRouter() (*gin.Engine, error) {
healthController.SetupRoutes()
// Setup OIDC controller if OIDC is enabled
if app.config.OIDC.Enabled && app.services.oidcService != nil {
oidcController := controller.NewOIDCController(controller.OIDCControllerConfig{
AppURL: app.config.AppURL,
CookieDomain: app.context.cookieDomain,
}, apiRouter, app.services.oidcService, app.services.authService)
oidcController.SetupRoutes()
}
return engine, nil
}

View File

@@ -13,6 +13,7 @@ type Services struct {
dockerService *service.DockerService
ldapService *service.LdapService
oauthBrokerService *service.OAuthBrokerService
oidcService *service.OIDCService
}
func (app *BootstrapApp) initServices() (Services, error) {
@@ -96,5 +97,39 @@ func (app *BootstrapApp) initServices() (Services, error) {
services.oauthBrokerService = oauthBrokerService
// Initialize OIDC service if enabled
if app.config.OIDC.Enabled {
issuer := app.config.OIDC.Issuer
if issuer == "" {
issuer = app.config.AppURL
}
oidcService := service.NewOIDCService(service.OIDCServiceConfig{
AppURL: app.config.AppURL,
Issuer: issuer,
AccessTokenExpiry: app.config.OIDC.AccessTokenExpiry,
IDTokenExpiry: app.config.OIDC.IDTokenExpiry,
Database: databaseService.GetDatabase(),
})
err = oidcService.Init()
if err != nil {
log.Warn().Err(err).Msg("Failed to initialize OIDC service, continuing without it")
} else {
services.oidcService = oidcService
log.Info().Msg("OIDC service initialized")
// Sync clients from config
if len(app.config.OIDC.Clients) > 0 {
err = oidcService.SyncClientsFromConfig(app.config.OIDC.Clients)
if err != nil {
log.Warn().Err(err).Msg("Failed to sync OIDC clients from config")
} else {
log.Info().Int("count", len(app.config.OIDC.Clients)).Msg("Synced OIDC clients from config")
}
}
}
}
return services, nil
}