1
0
forked from baron/baron-sso

fix(auth): separate pkce and headless trusted rp config

This commit is contained in:
Lectom C Han
2026-03-31 10:44:04 +09:00
parent 4b34ab8161
commit 33afe1eddf
8 changed files with 274 additions and 62 deletions

View File

@@ -1,6 +1,16 @@
package domain
import "time"
import (
"strings"
"time"
)
const (
MetadataHeadlessLoginEnabled = "headless_login_enabled"
MetadataHeadlessTokenEndpointAuthMethod = "headless_token_endpoint_auth_method"
MetadataHeadlessJWKSURI = "headless_jwks_uri"
MetadataHeadlessJWKS = "headless_jwks"
)
type HydraClient struct {
ClientID string `json:"client_id"`
@@ -20,11 +30,42 @@ type HydraClient struct {
func (c *HydraClient) IsTrustedRP() bool {
// A Trusted RP must have a public key registered (URI or Inline)
// and use private_key_jwt for token endpoint authentication.
hasPublicKey := c.JWKSUri != "" || c.JWKS != nil
isPrivateKeyJwt := c.TokenEndpointAuthMethod == "private_key_jwt"
hasPublicKey := c.HeadlessJWKSURI() != "" || c.HeadlessJWKS() != nil
isPrivateKeyJwt := c.HeadlessTokenEndpointAuthMethod() == "private_key_jwt"
return hasPublicKey && isPrivateKeyJwt
}
func (c *HydraClient) HeadlessTokenEndpointAuthMethod() string {
if c.Metadata != nil {
if raw, ok := c.Metadata[MetadataHeadlessTokenEndpointAuthMethod].(string); ok {
if value := strings.TrimSpace(raw); value != "" {
return value
}
}
}
return strings.TrimSpace(c.TokenEndpointAuthMethod)
}
func (c *HydraClient) HeadlessJWKSURI() string {
if c.Metadata != nil {
if raw, ok := c.Metadata[MetadataHeadlessJWKSURI].(string); ok {
if value := strings.TrimSpace(raw); value != "" {
return value
}
}
}
return strings.TrimSpace(c.JWKSUri)
}
func (c *HydraClient) HeadlessJWKS() interface{} {
if c.Metadata != nil {
if value, ok := c.Metadata[MetadataHeadlessJWKS]; ok && value != nil {
return value
}
}
return c.JWKS
}
func (c *HydraClient) IsHeadlessLoginEnabled() bool {
if !c.IsTrustedRP() {
return false
@@ -32,7 +73,7 @@ func (c *HydraClient) IsHeadlessLoginEnabled() bool {
if c.Metadata == nil {
return false
}
val, ok := c.Metadata["headless_login_enabled"]
val, ok := c.Metadata[MetadataHeadlessLoginEnabled]
if !ok {
return false
}

View File

@@ -3,6 +3,28 @@ package domain
import "testing"
func TestHydraClient_TrustedRPFlags(t *testing.T) {
t.Run("metadata-backed headless trusted rp is supported", func(t *testing.T) {
client := HydraClient{
TokenEndpointAuthMethod: "none",
Metadata: map[string]any{
"headless_login_enabled": true,
"headless_token_endpoint_auth_method": "private_key_jwt",
"headless_jwks": map[string]any{
"keys": []map[string]any{{
"kty": "RSA",
}},
},
},
}
if !client.IsTrustedRP() {
t.Fatalf("expected metadata-backed trusted rp")
}
if !client.IsHeadlessLoginEnabled() {
t.Fatalf("expected metadata-backed headless login enabled")
}
})
t.Run("inline jwks with private_key_jwt and headless enabled", func(t *testing.T) {
client := HydraClient{
TokenEndpointAuthMethod: "private_key_jwt",