Documentation
¶
Index ¶
- Constants
- func GenerateJwkSet(num int) (jwk.Set, error)
- func GenerateRandomJwk() (jwk.Key, error)
- func Logger(next http.Handler) http.Handler
- func OAuthErrors(next http.Handler) http.Handler
- func PublicJwkSet(set jwk.Set) (jwk.Set, error)
- func Recover(next http.Handler) http.Handler
- func ThumbprintS256(jwk jwk.Key) (string, error)
- type AuthzServerSession
- type AuthzServerSessionStore
- type Client
- type ClientAssertionClaims
- type ClientsRegistry
- type Config
- type EndpointsConfig
- type Error
- type ExtendedMetadata
- type IntrospectedSession
- type IntrospectionResponse
- type Metadata
- type OpenidProviderInfo
- type Product
- type ProductsRegistry
- type Server
- func (s *Server) AuthorizationEndpoint(w http.ResponseWriter, r *http.Request) error
- func (s *Server) GetOpenidClient(issuer string) (oidc.Client, error)
- func (s *Server) IntrospectionEndpoint(w http.ResponseWriter, r *http.Request) error
- func (s *Server) JWKS(w http.ResponseWriter, r *http.Request) error
- func (s *Server) MetadataEndpoint(w http.ResponseWriter, r *http.Request) error
- func (s *Server) MountRoutes(mux *http.ServeMux)
- func (s *Server) NonProdIssueTokens(sessionId string) (*TokenResponse, error)
- func (s *Server) NonProdStartSession(session *AuthzServerSession) error
- func (s *Server) NonceEndpoint(w http.ResponseWriter, r *http.Request) error
- func (s *Server) OPCallbackEndpoint(w http.ResponseWriter, r *http.Request) error
- func (s *Server) OpenidProviders() ([]OpenidProviderInfo, error)
- func (s *Server) OpenidProvidersEndpoint(w http.ResponseWriter, r *http.Request) error
- func (s *Server) PAREndpoint(w http.ResponseWriter, r *http.Request) error
- func (s *Server) RegistrationEndpoint(w http.ResponseWriter, r *http.Request) error
- func (s *Server) TokenEndpoint(w http.ResponseWriter, r *http.Request) error
- type StaticClientsRegistry
- type TokenResponse
Constants ¶
const ( GrantTypeAuthorizationCode = "authorization_code" GrantTypeClientCredentials = "client_credentials" GrantTypeRefreshToken = "refresh_token" )
const ClientAssertionTypeJWTBearer = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
ClientAssertionTypeJWTBearer is the client_assertion_type for private_key_jwt (RFC 7523 §2.2).
Variables ¶
This section is empty.
Functions ¶
func GenerateRandomJwk ¶
func OAuthErrors ¶
OAuthErrors normalizes any error response that is not already JSON (e.g. ServeMux's plain-text 404 / 405) into the OAuth JSON error shape, so ALL errors are OAuth-formatted.
Types ¶
type AuthzServerSession ¶
type AuthzServerSession struct {
ID string `json:"id"`
CreatedAt time.Time `json:"created_at"`
ExpiresAt time.Time `json:"expires_at"`
AccessTokenDuration time.Duration `json:"access_token_duration"`
Audience []string `json:"audience"`
ClientID string `json:"client_id"`
RedirectURI string `json:"redirect_uri"`
CodeChallenge string `json:"code_challenge"`
CodeChallengeMethod string `json:"code_challenge_method"`
State string `json:"state"`
Scopes []string `json:"scopes"`
IDPIss string `json:"idp_iss"`
RequestUri string `json:"request_uri"`
AuthnClientSession *oidc.AuthnClientSession `json:"authn_client_session"`
Code string `json:"code"`
RefreshToken string `json:"refresh_token"`
RefreshCount int `json:"refresh_count"`
LastRefreshAt time.Time `json:"last_refresh_at"`
DPoPThumbprint string `json:"dpop_thumbprint"`
}
type AuthzServerSessionStore ¶
type AuthzServerSessionStore interface {
GetAuthzServerSessionByID(id string) (*AuthzServerSession, error)
GetAuthzServerSessionByAuthnState(authnState string) (*AuthzServerSession, error)
GetAutzhServerSessionByRequestURI(requestURI string) (*AuthzServerSession, error)
GetAuthzServerSessionByCode(code string) (*AuthzServerSession, error)
GetAuthzServerSessionByRefreshToken(token string) (*AuthzServerSession, error)
DeleteRefreshIndex(refreshTokenHash string) error
SaveAutzhServerSession(session *AuthzServerSession) error
DeleteAuthzServerSessionByID(id string) error
}
type Client ¶ added in v0.22.0
type Client struct {
ClientID string `yaml:"client_id" json:"client_id" validate:"required"`
ProductID string `yaml:"product_id" json:"product_id" validate:"required"`
// PublicJWK is the client's assertion-verification key as a nested JWK object. It is parsed into
// a jwk.Key once at registry-build time (see Key).
PublicJWK map[string]any `yaml:"public_jwk" json:"public_jwk" validate:"required"`
// contains filtered or unexported fields
}
Client is a registered instance of a Product. A product may have many client instances; each authenticates with private_key_jwt (RFC 7523), proving itself with a client_assertion verified against PublicJWK. Redirect-URI and scope policy live on the Product the client belongs to.
type ClientAssertionClaims ¶
type ClientAssertionClaims struct {
Nonce string `json:"nonce" validate:"required"`
Iss string `json:"iss" validate:"required"`
Sub string `json:"sub" validate:"required"`
Aud []string `json:"aud" validate:"required"`
Iat int `json:"iat" validate:"required"`
Exp int `json:"exp" validate:"required"`
Cnf struct {
Jkt string `json:"jkt" validate:"required"`
} `json:"cnf" validate:"required"`
}
ClientAssertionClaims are the claims of a private_key_jwt client assertion. Beyond the standard RFC 7523 claims it keeps the gematik extensions: a nonce (redeemed against the AS nonce service) and cnf.jkt (the client's DPoP key, to which the issued access token is sender-constrained).
func (*ClientAssertionClaims) Validate ¶
func (c *ClientAssertionClaims) Validate() error
type ClientsRegistry ¶
type Config ¶
type Config struct {
BaseDir string `yaml:"-"`
Issuer string `yaml:"issuer" validate:"required"`
SignJwkPath string `yaml:"sign_jwk_path"`
ScopesSupported []string `yaml:"scopes_supported"`
MetadataTemplate ExtendedMetadata `yaml:"metadata_template"`
DefaultIDPIss string `yaml:"default_idp_iss"`
OidcProviders []oidc.Config `yaml:"oidc_providers" validate:"dive"`
GematikIdp []gemidp.ClientConfig `yaml:"gematik_idp" validate:"dive"`
ClientsPolicyPath string `yaml:"clients_policy_path"`
Products []Product `yaml:"products" validate:"omitempty,dive"`
Clients []Client `yaml:"clients" validate:"omitempty,dive"`
OidfRelyingPartyConfigPath string `yaml:"oidf_relying_party_path"`
OidfRelyingPartyConfig *oidf.RelyingPartyConfig `yaml:"oidf_relying_party" validate:"omitempty"`
Endpoints EndpointsConfig `yaml:"endpoints" validate:"omitempty"`
// some values may be set programmatically
NonceService nonce.Service
// Store is the kv backend for sessions + nonces. The command opens the Postgres store from
// DATABASE_URL (it owns the driver dependency) and injects it here; nil ⇒ an in-memory store
// (tests and dev).
Store kv.Store
}
type EndpointsConfig ¶
type EndpointsConfig struct {
AuthorizationServerMetadata string `yaml:"authorization_server_metadata"`
Jwks string `yaml:"jwks"`
Nonce string `yaml:"nonce"`
OpenIDProviders string `yaml:"openid_providers"`
Authorization string `yaml:"authorization"`
PushedAuthorizationRequest string `yaml:"pushed_authorization_request"`
OPCallback string `yaml:"op_callback"`
GemIDPCallback string `yaml:"gemidp_callback"`
Token string `yaml:"token"`
Introspection string `yaml:"introspection"`
EntityStatement string `yaml:"entity_statement"`
Registration string `yaml:"registration"`
}
type Error ¶
type Error struct {
HttpStatus int `json:"-"`
Code string `json:"error"`
Description string `json:"error_description,omitempty"`
URI string `json:"error_uri,omitempty"`
}
Error is an OAuth 2.0 error response (RFC 6749 §5.2). HttpStatus carries the HTTP status code and is not serialized.
type ExtendedMetadata ¶
type ExtendedMetadata struct {
Metadata
NonceEndpoint string `json:"nonce_endpoint"`
OpenidProvidersEndpoint string `json:"openid_providers_endpoint"`
}
Extend the standard OAuth2 server metadata from RFC8414
type IntrospectedSession ¶ added in v0.22.0
type IntrospectionResponse ¶ added in v0.22.0
type IntrospectionResponse struct {
Active bool `json:"active"`
Scope string `json:"scope,omitempty"`
ClientID string `json:"client_id,omitempty"`
Username string `json:"username,omitempty"`
TokenType string `json:"token_type,omitempty"`
Exp int64 `json:"exp,omitempty"`
Iat int64 `json:"iat,omitempty"`
Sub string `json:"sub,omitempty"`
Aud []string `json:"aud,omitempty"`
Iss string `json:"iss,omitempty"`
Jti string `json:"jti,omitempty"`
Cnf map[string]any `json:"cnf,omitempty"`
// Extension members: the upstream identity this session was established with, and session details.
Identity map[string]any `json:"identity,omitempty"`
IDToken string `json:"id_token,omitempty"`
Session *IntrospectedSession `json:"session,omitempty"`
}
IntrospectionResponse is the OAuth 2.0 Token Introspection response (RFC 7662), extended per §2.2 with the brokered upstream OIDC identity and session metadata as service-specific members.
type Metadata ¶
type Metadata struct {
Issuer string `json:"issuer" yaml:"issuer"`
AuthorizationEndpoint string `json:"authorization_endpoint" yaml:"authorization_endpoint"`
TokenEndpoint string `json:"token_endpoint" yaml:"token_endpoint"`
JwksURI string `json:"jwks_uri,omitempty" yaml:"jwks_uri"`
RegistrationEndpoint string `json:"registration_endpoint,omitempty" yaml:"registration_endpoint"`
ScopesSupported []string `json:"scopes_supported" yaml:"scopes_supported"`
ResponseTypesSupported []string `json:"response_types_supported" yaml:"response_types_supported"`
ResponseModesSupported []string `json:"response_modes_supported" yaml:"response_modes_supported"`
GrantTypesSupported []string `json:"grant_types_supported" yaml:"grant_types_supported"`
TokenEndpointAuthMethodsSupported []string `json:"token_endpoint_auth_methods_supported" yaml:"token_endpoint_auth_methods_supported"`
TokenEndpointAuthSigningAlgValuesSupported []string `json:"token_endpoint_auth_signing_alg_values_supported" yaml:"token_endpoint_auth_signing_alg_values_supported"`
ServiceDocumentation string `json:"service_documentation,omitempty" yaml:"service_documentation"`
UILocalesSupported []string `json:"ui_locales_supported,omitempty" yaml:"ui_locales_supported"`
OPPolicyURI string `json:"op_policy_uri,omitempty" yaml:"op_policy_uri"`
OPTosURI string `json:"op_tos_uri,omitempty" yaml:"op_tos_uri"`
RevocationEndpoint string `json:"revocation_endpoint,omitempty" yaml:"revocation_endpoint"`
RevocationEndpointAuthMethodsSupported []string `json:"revocation_endpoint_auth_methods_supported,omitempty" yaml:"revocation_endpoint_auth_methods_supported"`
RevocationEndpointAuthSigningAlgValuesSupported []string `` /* 131-byte string literal not displayed */
IntrospectionEndpoint string `json:"introspection_endpoint,omitempty" yaml:"introspection_endpoint"`
IntrospectionEndpointAuthMethodsSupported []string `json:"introspection_endpoint_auth_methods_supported,omitempty" yaml:"introspection_endpoint_auth_methods_supported"`
IntrospectionEndpointAuthSigningAlgValuesSupported []string `` /* 137-byte string literal not displayed */
CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported" yaml:"code_challenge_methods_supported"`
PushedAuthorizationRequestEndpoint string `json:"pushed_authorization_request_endpoint,omitempty" yaml:"pushed_authorization_request_endpoint"`
RequirePushedAuthorizationRequests bool `json:"require_pushed_authorization_requests,omitempty" yaml:"require_pushed_authorization_requests"`
}
OAuth2 Authorization Server Metadata See https://datatracker.ietf.org/doc/html/rfc8414
type OpenidProviderInfo ¶
type OpenidProviderInfo struct {
Issuer string `json:"iss"`
LogoURI string `json:"logo_uri"`
Name string `json:"name"`
Type string `json:"type"`
}
OpenidProviderInfo represents the information about an OpenID Provider
type Product ¶ added in v0.22.0
type Product struct {
ProductID string `yaml:"product_id" json:"product_id" validate:"required"`
ProductName string `yaml:"product_name" json:"product_name"`
ManufacturerID string `yaml:"manufacturer_id" json:"manufacturer_id"`
ManufacturerName string `yaml:"manufacturer_name" json:"manufacturer_name"`
Platform string `yaml:"platform" json:"platform"`
PlatformProductID any `yaml:"platform_product_id" json:"platform_product_id"`
RedirectURIs []string `yaml:"redirect_uris" json:"redirect_uris"`
Scopes []string `yaml:"scopes" json:"scopes"`
// OIDCRedirectURIs are the redirect_uri(s) the upstream IdP sends the user back to the AS at (gematik
// oidc_redirect_uri), instead of the default /op-callback — so the IdP redirects straight to the AS with
// no app-side intermediary popup. Registered into the OIDF entity statement (see initRelyingParty).
OIDCRedirectURIs []string `yaml:"oidc_redirect_uris" json:"oidc_redirect_uris"`
PushGateway any `yaml:"push_gateway" json:"push_gateway"`
}
Product is an application registered with the authorization server. It owns the redirect-URI and scope policy that all of its client instances share. Products are loaded inline from the config (products:) and/or from a gematik clients-policy file (clients_policy_path).
func LoadProductsFile ¶ added in v0.22.0
LoadProductsFile reads a gematik clients-policy file, whose top-level key is `clients`.
func (*Product) IsAllowedRedirectURI ¶ added in v0.22.0
func (*Product) IsAllowedScope ¶ added in v0.22.0
func (*Product) IsAllowedScopes ¶ added in v0.22.0
type ProductsRegistry ¶ added in v0.22.0
type ProductsRegistry struct {
// contains filtered or unexported fields
}
func NewProductsRegistry ¶ added in v0.22.0
func NewProductsRegistry(products []*Product) *ProductsRegistry
func (*ProductsRegistry) AllOIDCRedirectURIs ¶ added in v0.22.0
func (r *ProductsRegistry) AllOIDCRedirectURIs() []string
AllOIDCRedirectURIs returns the deduplicated oidc_redirect_uri across every product — the redirect URIs the upstream IdP may send the user back to the AS at. They are injected into the OIDF entity statement.
func (*ProductsRegistry) GetProduct ¶ added in v0.22.0
func (r *ProductsRegistry) GetProduct(productID string) (*Product, error)
type Server ¶
type Server struct {
Metadata ExtendedMetadata
// contains filtered or unexported fields
}
func NewFromConfigFile ¶
func (*Server) AuthorizationEndpoint ¶
func (*Server) GetOpenidClient ¶
GetOpenidClient returns an OpenID Connect client for the given issuer
func (*Server) IntrospectionEndpoint ¶ added in v0.22.0
IntrospectionEndpoint implements OAuth 2.0 Token Introspection (RFC 7662). The caller must authenticate as a client, and only the client a token was issued to may introspect it; any other outcome answers {"active": false} so a token is never revealed to a party that does not own it.
func (*Server) MetadataEndpoint ¶
MetadataEndpoint serves the authorization server metadata document (RFC 8414).
func (*Server) MountRoutes ¶
MountRoutes registers the authorization server routes on the given ServeMux. Each handler is wrapped by s.handle, which renders returned errors as OAuth JSON (RFC 6749 §5.2).
func (*Server) NonProdIssueTokens ¶
func (s *Server) NonProdIssueTokens(sessionId string) (*TokenResponse, error)
func (*Server) NonProdStartSession ¶
func (s *Server) NonProdStartSession(session *AuthzServerSession) error
Non-production code for the OAuth2 server
func (*Server) NonceEndpoint ¶
NonceEndpoint returns a fresh replay nonce as a text/plain body (GET only).
func (*Server) OPCallbackEndpoint ¶
OPCallbackEndpoint handles the callback from the OpenID Provider
func (*Server) OpenidProviders ¶
func (s *Server) OpenidProviders() ([]OpenidProviderInfo, error)
OpenidProviders returns the list of OpenID Providers supported by the server
func (*Server) OpenidProvidersEndpoint ¶
OpenidProvidersEndpoint serves the list of OpenID Providers supported by the server
func (*Server) PAREndpoint ¶
PAREndpoint (RFC 9126) accepts a client-authenticated pushed authorization request: it validates the parameters exactly as /authorize would, stores them, and returns a single-use request_uri the client then hands to /authorize. FAPI 2.0 requires this — the request is integrity-protected (back-channel, private_key_jwt) rather than carried in the browser URL.
func (*Server) RegistrationEndpoint ¶
RegistrationEndpoint is intentionally closed. Clients are provisioned out-of-band (operator config now, federation later), so dynamic client registration (RFC 7591) is not offered. The endpoint stays advertised in the metadata and returns a coherent OAuth error — the same shape as every other endpoint — rather than a bare 404, leaving a clean seam to enable gated registration later (swap this body, add storage).
func (*Server) TokenEndpoint ¶
TokenEndpoint handles the token request for various grant types
type StaticClientsRegistry ¶
type StaticClientsRegistry struct {
// contains filtered or unexported fields
}
func NewStaticClientsRegistry ¶ added in v0.22.0
func NewStaticClientsRegistry(clients []Client) (*StaticClientsRegistry, error)
NewStaticClientsRegistry parses each client's public JWK and indexes the clients by client_id.