Package rfc8414

import "funnyhaha.technology/rfc/rfc8414"
View the source code

Overview

Package rfc8414 implements OAuth 2.0 Authorization Server Metadata, from RFC 8414: the JSON document an authorization server publishes at a well-known URL, so clients can find its endpoints and capabilities.

A server builds its document once, while wiring:

md := rfc8414.Metadata{
	Issuer:                 "https://as.example.com",
	AuthorizationEndpoint:  "https://as.example.com/authorize",
	TokenEndpoint:          "https://as.example.com/token",
	ResponseTypesSupported: []string{"code"},
}.WithExtension("client_id_metadata_document_supported", true)

and serves it at the path WellKnownURL gives. A client fetches it from there, and checks it with Metadata.CheckIssuer.

The package doesn't cover signed metadata (Section 2.1).

The RFC text is in rfc8414.txt in this directory, and the doc comments cite its sections.

Index

Constants

const WellKnownSuffix = "oauth-authorization-server"
source

WellKnownSuffix is the well-known URI suffix for authorization server metadata (Section 3).

Variables

var (
	// ErrInvalidIssuer is returned by [ParseIssuer] and [WellKnownURL] for
	// an issuer identifier that isn't an https URL without a query or
	// fragment.
	ErrInvalidIssuer = errors.New("invalid issuer identifier")

	// ErrIssuerMismatch is returned by [Metadata.CheckIssuer] when a
	// metadata document's issuer isn't the one it was fetched for.
	ErrIssuerMismatch = errors.New("issuer mismatch")
)
source

Functions

ParseIssuer source

func ParseIssuer(s string) (string, error)

ParseIssuer returns s if it's a valid issuer identifier: an https URL with no query or fragment (Section 2). Otherwise it returns ErrInvalidIssuer.

WellKnownURL source

func WellKnownURL(issuer string) (string, error)

WellKnownURL returns the URL of the metadata document for the issuer: the well-known path inserted between the host and any path, with the path's trailing "/" removed (Section 3.1). It returns ErrInvalidIssuer if the issuer isn't an absolute URL.

It accepts an http issuer, for testing against a local server, though ParseIssuer doesn't.

Types

Metadata source

type Metadata struct {
	Issuer                                     string   `json:"issuer"`
	AuthorizationEndpoint                      string   `json:"authorization_endpoint,omitempty"`
	TokenEndpoint                              string   `json:"token_endpoint,omitempty"`
	JWKSURI                                    string   `json:"jwks_uri,omitempty"`
	RegistrationEndpoint                       string   `json:"registration_endpoint,omitempty"`
	ScopesSupported                            []string `json:"scopes_supported,omitempty"`
	ResponseTypesSupported                     []string `json:"response_types_supported"`
	ResponseModesSupported                     []string `json:"response_modes_supported,omitempty"`
	GrantTypesSupported                        []string `json:"grant_types_supported,omitempty"`
	TokenEndpointAuthMethodsSupported          []string `json:"token_endpoint_auth_methods_supported,omitempty"`
	TokenEndpointAuthSigningAlgValuesSupported []string `json:"token_endpoint_auth_signing_alg_values_supported,omitempty"`
	ServiceDocumentation                       string   `json:"service_documentation,omitempty"`
	UILocalesSupported                         []string `json:"ui_locales_supported,omitempty"`
	OPPolicyURI                                string   `json:"op_policy_uri,omitempty"`
	OPTOSURI                                   string   `json:"op_tos_uri,omitempty"`
	RevocationEndpoint                         string   `json:"revocation_endpoint,omitempty"`
	//nolint:lll // The JSON member names are the RFC's.
	RevocationEndpointAuthMethodsSupported []string `json:"revocation_endpoint_auth_methods_supported,omitempty"`
	//nolint:lll // The JSON member names are the RFC's.
	RevocationEndpointAuthSigningAlgValuesSupported []string `json:"revocation_endpoint_auth_signing_alg_values_supported,omitempty"`
	IntrospectionEndpoint                           string   `json:"introspection_endpoint,omitempty"`
	//nolint:lll // The JSON member names are the RFC's.
	IntrospectionEndpointAuthMethodsSupported []string `json:"introspection_endpoint_auth_methods_supported,omitempty"`
	//nolint:lll // The JSON member names are the RFC's.
	IntrospectionEndpointAuthSigningAlgValuesSupported []string `json:"introspection_endpoint_auth_signing_alg_values_supported,omitempty"`
	CodeChallengeMethodsSupported                      []string `json:"code_challenge_methods_supported,omitempty"`
	// contains filtered or unexported fields
}

Metadata is an authorization server metadata document, with the members Section 2 defines and any extension members. Set the standard members directly, and extension members with Metadata.WithExtension.

Metadata has its own MarshalJSON and UnmarshalJSON, so extension members are kept by both encoding/json and encoding/json/v2.

See RFC 8414, Section 2.

(Metadata) CheckIssuer source

func (m Metadata) CheckIssuer(issuer string) error

CheckIssuer returns ErrIssuerMismatch unless m's issuer is identical to the issuer the client built the metadata URL from. Section 3.3 says a client MUST check this, or an attacker can impersonate another authorization server.

(Metadata) Extension source

func (m Metadata) Extension(name string, v any) (bool, error)

Extension unmarshals the extension member with the name into v, as json.Unmarshal does. It reports false if m has no such member.

(Metadata) MarshalJSON source

func (m Metadata) MarshalJSON() ([]byte, error)

MarshalJSON returns m as a JSON object: the standard members, leaving out empty optional ones, then extension members sorted by name.

(Metadata) UnmarshalJSON source

func (m *Metadata) UnmarshalJSON(data []byte) error

UnmarshalJSON reads a metadata document, keeping members it doesn't define as extension members.

(Metadata) WithExtension source

func (m Metadata) WithExtension(name string, value any) Metadata

WithExtension returns a copy of m with an extension member, such as "client_id_metadata_document_supported", replacing any with the same name. The value is marshalled when m is, so Metadata.MarshalJSON returns an error if it can't be, or if the name is a standard member's.