feat: add support for client secret post auth to oidc token endpoint

This commit is contained in:
Stavros
2026-02-07 21:04:58 +02:00
parent baf4798665
commit 22c4c262ea
2 changed files with 38 additions and 15 deletions

View File

@@ -33,6 +33,8 @@ type TokenRequest struct {
Code string `form:"code" url:"code"`
RedirectURI string `form:"redirect_uri" url:"redirect_uri"`
RefreshToken string `form:"refresh_token" url:"refresh_token"`
ClientSecret string `form:"client_secret" url:"client_secret"`
ClientID string `form:"client_id" url:"client_id"`
}
type CallbackError struct {
@@ -49,6 +51,11 @@ type ClientRequest struct {
ClientID string `uri:"id" binding:"required"`
}
type ClientCredentials struct {
ClientID string
ClientSecret string
}
func NewOIDCController(config OIDCControllerConfig, oidcService *service.OIDCService, router *gin.RouterGroup) *OIDCController {
return &OIDCController{
config: config,
@@ -210,29 +217,45 @@ func (controller *OIDCController) Token(c *gin.Context) {
return
}
rclientId, rclientSecret, ok := c.Request.BasicAuth()
if !ok {
tlog.App.Error().Msg("Missing authorization header")
c.Header("www-authenticate", "basic")
c.JSON(401, gin.H{
"error": "invalid_client",
})
return
// First we try form values
creds := ClientCredentials{
ClientID: req.ClientID,
ClientSecret: req.ClientSecret,
}
client, ok := controller.oidc.GetClient(rclientId)
// If it fails, we try basic auth
if creds.ClientID == "" || creds.ClientSecret == "" {
tlog.App.Debug().Msg("Tried form values and they are empty, trying basic auth")
clientId, clientSecret, ok := c.Request.BasicAuth()
if !ok {
tlog.App.Error().Msg("Missing authorization header")
c.Header("www-authenticate", "basic")
c.JSON(401, gin.H{
"error": "invalid_client",
})
return
}
creds.ClientID = clientId
creds.ClientSecret = clientSecret
}
// END - we don't support other authentication methods
client, ok := controller.oidc.GetClient(creds.ClientID)
if !ok {
tlog.App.Warn().Str("client_id", rclientId).Msg("Client not found")
tlog.App.Warn().Str("client_id", creds.ClientID).Msg("Client not found")
c.JSON(400, gin.H{
"error": "invalid_client",
})
return
}
if client.ClientSecret != rclientSecret {
tlog.App.Warn().Str("client_id", rclientId).Msg("Invalid client secret")
if client.ClientSecret != creds.ClientSecret {
tlog.App.Warn().Str("client_id", creds.ClientID).Msg("Invalid client secret")
c.JSON(400, gin.H{
"error": "invalid_client",
})
@@ -286,7 +309,7 @@ func (controller *OIDCController) Token(c *gin.Context) {
tokenResponse = tokenRes
case "refresh_token":
tokenRes, err := controller.oidc.RefreshAccessToken(c, req.RefreshToken, rclientId)
tokenRes, err := controller.oidc.RefreshAccessToken(c, req.RefreshToken, creds.ClientID)
if err != nil {
if errors.Is(err, service.ErrTokenExpired) {

View File

@@ -58,7 +58,7 @@ func (controller *WellKnownController) OpenIDConnectConfiguration(c *gin.Context
GrantTypesSupported: service.SupportedGrantTypes,
SubjectTypesSupported: []string{"pairwise"},
IDTokenSigningAlgValuesSupported: []string{"RS256"},
TokenEndpointAuthMethodsSupported: []string{"client_secret_basic"},
TokenEndpointAuthMethodsSupported: []string{"client_secret_basic", "client_secret_post"},
ClaimsSupported: []string{"sub", "updated_at", "name", "preferred_username", "email", "groups"},
ServiceDocumentation: "https://tinyauth.app/docs/reference/openid",
})