From a8f57e584e9fbe7a803e7d24df74511da6270be5 Mon Sep 17 00:00:00 2001 From: Stavros Date: Mon, 26 Jan 2026 19:50:15 +0200 Subject: [PATCH] feat: openid discovery endpoint --- Makefile | 4 +- frontend/vite.config.ts | 5 ++ internal/bootstrap/router_bootstrap.go | 6 ++ internal/controller/well_known_controller.go | 62 ++++++++++++++++++++ internal/middleware/ui_middleware.go | 8 +-- 5 files changed, 79 insertions(+), 6 deletions(-) create mode 100644 internal/controller/well_known_controller.go diff --git a/Makefile b/Makefile index 0c2a1b7..55d6c93 100644 --- a/Makefile +++ b/Makefile @@ -61,11 +61,11 @@ test: # Development develop: - docker compose -f $(DEV_COMPOSE) up --force-recreate --pull=always --remove-orphans + docker compose -f $(DEV_COMPOSE) up --force-recreate --pull=always --remove-orphans --build # Development - Infisical develop-infisical: - infisical run --env=dev -- docker compose -f $(DEV_COMPOSE) up --force-recreate --pull=always --remove-orphans + infisical run --env=dev -- docker compose -f $(DEV_COMPOSE) up --force-recreate --pull=always --remove-orphans --build # Production prod: diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index f391a49..bedce8e 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -24,6 +24,11 @@ export default defineConfig({ changeOrigin: true, rewrite: (path) => path.replace(/^\/resources/, ""), }, + "/.well-known": { + target: "http://tinyauth-backend:3000/.well-known", + changeOrigin: true, + rewrite: (path) => path.replace(/^\/.well-known/, ""), + }, }, allowedHosts: true, }, diff --git a/internal/bootstrap/router_bootstrap.go b/internal/bootstrap/router_bootstrap.go index 1a54489..b64bfe0 100644 --- a/internal/bootstrap/router_bootstrap.go +++ b/internal/bootstrap/router_bootstrap.go @@ -113,5 +113,11 @@ func (app *BootstrapApp) setupRouter() (*gin.Engine, error) { healthController.SetupRoutes() + wellknownController := controller.NewWellKnownController(controller.WellKnownControllerConfig{ + OpenIDConnectIssuer: app.services.oidcService.GetIssuer(), + }, engine) + + wellknownController.SetupRoutes() + return engine, nil } diff --git a/internal/controller/well_known_controller.go b/internal/controller/well_known_controller.go new file mode 100644 index 0000000..e032c1e --- /dev/null +++ b/internal/controller/well_known_controller.go @@ -0,0 +1,62 @@ +package controller + +import ( + "fmt" + + "github.com/gin-gonic/gin" + "github.com/steveiliop56/tinyauth/internal/service" +) + +type OpenIDConnectConfiguration struct { + Issuer string `json:"issuer"` + AuthorizationEndpoint string `json:"authorization_endpoint"` + TokenEndpoint string `json:"token_endpoint"` + UserinfoEndpoint string `json:"userinfo_endpoint"` + JwksUri string `json:"jwks_uri"` + ScopesSupported []string `json:"scopes_supported"` + ResponseTypesSupported []string `json:"response_types_supported"` + GrantTypesSupported []string `json:"grant_types_supported"` + SubjectTypesSupported []string `json:"subject_types_supported"` + IDTokenSigningAlgValuesSupported []string `json:"id_token_signing_alg_values_supported"` + TokenEndpointAuthMethodsSupported []string `json:"token_endpoint_auth_methods_supported"` + ClaimsSupported []string `json:"claims_supported"` + ServiceDocumentation string `json:"service_documentation"` +} + +type WellKnownControllerConfig struct { + OpenIDConnectIssuer string +} + +type WellKnownController struct { + config WellKnownControllerConfig + engine *gin.Engine +} + +func NewWellKnownController(config WellKnownControllerConfig, engine *gin.Engine) *WellKnownController { + return &WellKnownController{ + config: config, + engine: engine, + } +} + +func (controller *WellKnownController) SetupRoutes() { + controller.engine.GET("/.well-known/openid-configuration", controller.OpenIDConnectConfiguration) +} + +func (controller *WellKnownController) OpenIDConnectConfiguration(c *gin.Context) { + c.JSON(200, OpenIDConnectConfiguration{ + Issuer: controller.config.OpenIDConnectIssuer, + AuthorizationEndpoint: fmt.Sprintf("%s/authorize", controller.config.OpenIDConnectIssuer), + TokenEndpoint: fmt.Sprintf("%s/api/oidc/token", controller.config.OpenIDConnectIssuer), + UserinfoEndpoint: fmt.Sprintf("%s/api/oidc/userinfo", controller.config.OpenIDConnectIssuer), + JwksUri: fmt.Sprintf("%s/api/oidc/jwks", controller.config.OpenIDConnectIssuer), + ScopesSupported: service.SupportedScopes, + ResponseTypesSupported: service.SupportedResponseTypes, + GrantTypesSupported: service.SupportedGrantTypes, + SubjectTypesSupported: []string{"pairwise"}, + IDTokenSigningAlgValuesSupported: []string{"RS256"}, + TokenEndpointAuthMethodsSupported: []string{"client_secret_basic"}, + ClaimsSupported: []string{"sub", "updated_at", "name", "preferred_username", "email", "groups"}, + ServiceDocumentation: "https://tinyauth.app/docs/reference/openid", + }) +} diff --git a/internal/middleware/ui_middleware.go b/internal/middleware/ui_middleware.go index 59a5da9..4086d77 100644 --- a/internal/middleware/ui_middleware.go +++ b/internal/middleware/ui_middleware.go @@ -9,6 +9,7 @@ import ( "time" "github.com/steveiliop56/tinyauth/internal/assets" + "github.com/steveiliop56/tinyauth/internal/utils/tlog" "github.com/gin-gonic/gin" ) @@ -39,11 +40,10 @@ func (m *UIMiddleware) Middleware() gin.HandlerFunc { return func(c *gin.Context) { path := strings.TrimPrefix(c.Request.URL.Path, "/") + tlog.App.Debug().Str("path", path).Msg("path") + switch strings.SplitN(path, "/", 2)[0] { - case "api": - c.Next() - return - case "resources": + case "api", "resources", ".well-known": c.Next() return default: