Tooling to load and parse Openid Configuration.
Records
To use the record, import the definition:
-include_lib(["oidcc/include/oidcc_provider_configuration.hrl"]).Telemetry
Summary
Types
Decoded JSON document as served by the provider.
Decoded JWKS document as served by the provider.
Configure configuration loading / parsing.
Allow Specification Non-compliance.
Record containing OpenID and OAuth 2.0 Configuration.
Functions
Decode JSON into a oidcc_provider_configuration:t/0 record.
Load OpenID Configuration into a oidcc_provider_configuration:t/0 record.
Load OpenID Configuration, keeping the document the provider served.
Load JWKs into a jose_jwk:key/0 record.
Load JWKs, keeping the document the provider served.
Types
Decoded JSON document as served by the provider.
This is the document the endpoint returned, before oidcc merges
document_overrides into it or coerces it into a record. Unlike a decoded
record it can be re-encoded losslessly, which is what makes it suitable for
persisting the provider's metadata.
-type error() :: invalid_content_type | {issuer_mismatch, Issuer :: binary()} | {invalid_issuer, Issuer :: binary()} | {invalid_document, Document :: term()} | oidcc_decode_util:error() | oidcc_http_util:error().
Decoded JWKS document as served by the provider.
RFC 7517 section 5 defines a JWK Set as a JSON object with a keys member, but
jose_jwk:from/1 also accepts a bare array of keys and some providers serve
one, so both shapes reach the caller.
-type opts() :: #{fallback_expiry => timeout(), request_opts => oidcc_http_util:request_opts(), quirks => quirks()}.
Configure configuration loading / parsing.
Parameters
fallback_expiry- How long to keep configuration cached if the server doesn't specify expiry.request_opts- config for HTTP request.
-type quirks() :: #{allow_unsafe_http => boolean(), document_overrides => map(), issuer_regex => binary()}.
Allow Specification Non-compliance.
Exceptions
allow_unsafe_http- Allow unsafe HTTP. Use this for development providers and never in production.document_overrides- a map to merge with the real OIDD document, in case the OP left out some values.issuer_regex- Optional regex pattern to match against the issuer claim instead of requiring an exact match. This may be necessary for certain providers that do not conform to the OpenID specification, such as Microsoft Entra ID where the issuer is 'https://login.microsoftonline.com/{tenantid}/v2.0' in the OpenID configuration.
-type t() :: #oidcc_provider_configuration{issuer :: uri_string:uri_string(), issuer_regex :: binary() | undefined, authorization_endpoint :: uri_string:uri_string(), token_endpoint :: uri_string:uri_string() | undefined, userinfo_endpoint :: uri_string:uri_string() | undefined, jwks_uri :: uri_string:uri_string() | undefined, registration_endpoint :: uri_string:uri_string() | undefined, scopes_supported :: [binary()] | undefined, response_types_supported :: [binary()], response_modes_supported :: [binary()], grant_types_supported :: [binary()], acr_values_supported :: [binary()] | undefined, subject_types_supported :: [pairwise | public], id_token_signing_alg_values_supported :: [binary()], id_token_encryption_alg_values_supported :: [binary()] | undefined, id_token_encryption_enc_values_supported :: [binary()] | undefined, userinfo_signing_alg_values_supported :: [binary()] | undefined, userinfo_encryption_alg_values_supported :: [binary()] | undefined, userinfo_encryption_enc_values_supported :: [binary()] | undefined, request_object_signing_alg_values_supported :: [binary()] | undefined, request_object_encryption_alg_values_supported :: [binary()] | undefined, request_object_encryption_enc_values_supported :: [binary()] | undefined, token_endpoint_auth_methods_supported :: [binary()], token_endpoint_auth_signing_alg_values_supported :: [binary()] | undefined, display_values_supported :: [binary()] | undefined, claim_types_supported :: [normal | aggregated | distributed], claims_supported :: [binary()] | undefined, service_documentation :: uri_string:uri_string() | undefined, claims_locales_supported :: [binary()] | undefined, ui_locales_supported :: [binary()] | undefined, claims_parameter_supported :: boolean(), request_parameter_supported :: boolean(), request_uri_parameter_supported :: boolean(), require_request_uri_registration :: boolean(), op_policy_uri :: uri_string:uri_string() | undefined, op_tos_uri :: uri_string:uri_string() | undefined, revocation_endpoint :: uri_string:uri_string() | undefined, revocation_endpoint_auth_methods_supported :: [binary()], revocation_endpoint_auth_signing_alg_values_supported :: [binary()] | undefined, introspection_endpoint :: uri_string:uri_string() | undefined, introspection_endpoint_auth_methods_supported :: [binary()], introspection_endpoint_auth_signing_alg_values_supported :: [binary()] | undefined, code_challenge_methods_supported :: [binary()] | undefined, end_session_endpoint :: uri_string:uri_string() | undefined, require_pushed_authorization_requests :: boolean(), pushed_authorization_request_endpoint :: uri_string:uri_string() | undefined, authorization_signing_alg_values_supported :: [binary()] | undefined, authorization_encryption_alg_values_supported :: [binary()] | undefined, authorization_encryption_enc_values_supported :: [binary()] | undefined, authorization_response_iss_parameter_supported :: boolean(), dpop_signing_alg_values_supported :: [binary()] | undefined, require_signed_request_object :: boolean(), mtls_endpoint_aliases :: #{binary() => uri_string:uri_string()}, extra_fields :: #{binary() => term()}, tls_client_certificate_bound_access_tokens :: boolean()}.
Record containing OpenID and OAuth 2.0 Configuration.
See:
- https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata
- https://datatracker.ietf.org/doc/html/draft-jones-oauth-discovery-01#section-4.1
- https://openid.net/specs/openid-connect-rpinitiated-1_0.html#OPMetadata
All unrecognized fields are stored in extra_fields.
Functions
-spec decode_configuration(Configuration, Opts) -> {ok, t()} | {error, error()} when Configuration :: map(), Opts :: opts().
Decode JSON into a oidcc_provider_configuration:t/0 record.
Examples
{ok, {{"HTTP/1.1",200,"OK"}, _Headers, Body}} =
httpc:request("https://accounts.google.com/.well-known/openid-configuration"),
{ok, DecodedJson} = your_json_lib:decode(Body),
{ok, #oidcc_provider_configuration{}} =
oidcc_provider_configuration:decode_configuration(DecodedJson).
-spec load_configuration(Issuer) -> {ok, {Configuration :: t(), Expiry :: pos_integer()}} | {error, error()} when Issuer :: uri_string:uri_string().
See load_configuration/2.
-spec load_configuration(Issuer, Opts) -> {ok, {Configuration :: t(), Expiry :: pos_integer()}} | {error, error()} when Issuer :: uri_string:uri_string(), Opts :: opts().
Load OpenID Configuration into a oidcc_provider_configuration:t/0 record.
Examples
{ok, #oidcc_provider_configuration{}} =
oidcc_provider_configuration:load_configuration("https://accounts.google.com").
-spec load_configuration_raw(Issuer, Opts) -> {ok, {Configuration :: t(), Expiry :: pos_integer(), Document :: document()}} | {error, error()} when Issuer :: uri_string:uri_string(), Opts :: opts().
Load OpenID Configuration, keeping the document the provider served.
Same as load_configuration/2, but additionally returns the decoded JSON
document. The record cannot be re-encoded losslessly - extra_fields holds only
the keys the decoder did not recognize, every other key is coerced into a typed
record field, and issuer_regex is not an OpenID Discovery field at all - so
callers that persist provider metadata need the document itself.
Examples
{ok, {#oidcc_provider_configuration{}, _Expiry, #{<<"issuer">> := Issuer}}} =
oidcc_provider_configuration:load_configuration_raw(
"https://accounts.google.com",
#{}
).
-spec load_jwks(JwksUri, Opts) -> {ok, {Jwks :: jose_jwk:key(), Expiry :: pos_integer()}} | {error, term()} when JwksUri :: uri_string:uri_string(), Opts :: opts().
Load JWKs into a jose_jwk:key/0 record.
Examples
{ok, #jose_jwk{}} =
oidcc_provider_configuration:load_jwks("https://www.googleapis.com/oauth2/v3/certs").
-spec load_jwks_raw(JwksUri, Opts) -> {ok, {Jwks :: jose_jwk:key(), Expiry :: pos_integer(), Document :: jwks_document()}} | {error, error()} when JwksUri :: uri_string:uri_string(), Opts :: opts().
Load JWKs, keeping the document the provider served.
Same as load_jwks/2, but additionally returns the decoded JSON document, for
callers that persist the key set rather than only using it.
Examples
{ok, {#jose_jwk{}, _Expiry, #{<<"keys">> := _Keys}}} =
oidcc_provider_configuration:load_jwks_raw(
"https://www.googleapis.com/oauth2/v3/certs",
#{}
).