#[non_exhaustive]pub struct AuthorizationServerMetadata {Show 26 fields
pub issuer: String,
pub authorization_endpoint: String,
pub token_endpoint: String,
pub device_authorization_endpoint: String,
pub introspection_endpoint: Option<String>,
pub revocation_endpoint: Option<String>,
pub registration_endpoint: Option<String>,
pub jwks_uri: Option<String>,
pub scopes_supported: Option<Vec<String>>,
pub pushed_authorization_request_endpoint: Option<String>,
pub require_pushed_authorization_requests: Option<bool>,
pub request_object_signing_alg_values_supported: Option<Vec<String>>,
pub require_signed_request_object: Option<bool>,
pub response_types_supported: Vec<String>,
pub response_modes_supported: Vec<String>,
pub grant_types_supported: Vec<String>,
pub token_endpoint_auth_methods_supported: Vec<String>,
pub token_endpoint_auth_signing_alg_values_supported: Option<Vec<String>>,
pub dpop_signing_alg_values_supported: Option<Vec<String>>,
pub code_challenge_methods_supported: Vec<String>,
pub service_documentation: Option<String>,
pub protected_resources: Option<Vec<String>>,
pub authorization_details_types_supported: Option<Vec<String>>,
pub client_id_metadata_document_supported: bool,
pub authorization_response_iss_parameter_supported: bool,
pub tls_client_certificate_bound_access_tokens: bool,
}Expand description
An RFC 8414 authorization server metadata document.
Optional members are Option and are OMITTED when absent, never serialized as null: RFC
8414 defines member types, and null is not one of them.
#[non_exhaustive]: five features (par, jar, rar, mtls, resource-metadata) each add a
member, which is what an RFC 8414 document IS: the list of what this build can do. A host builds
this with AuthorizationServerMetadata::from_config, which is the only way to get a document
that agrees with the server that will answer the requests it advertises; a literal written by
hand is a document that describes a server nobody has to match. Deserialize is derived here
and is unaffected, so a client-side or test-side consumer parsing one still works.
Fields (Non-exhaustive)§
This struct is marked as non-exhaustive
Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.issuer: StringREQUIRED (section 2). The AS’s issuer identifier; must equal the URL this document was retrieved from, minus the well-known path (section 3.3), and carries no query or fragment.
REQUIRED for an AS supporting the authorization code grant (section 2).
token_endpoint: StringREQUIRED unless only the implicit grant is supported, which OAuth 2.1 removes (section 2).
RFC 8628 section 4: how an AS advertises device grant support.
introspection_endpoint: Option<String>RFC 7662 section 2. Present ONLY when the host named
ServerConfig::introspection_endpoint, and absent otherwise.
§Why this one is opt-in and the others are not
RFC 7662’s primary consumer is a PROTECTED RESOURCE — the abstract defines the whole
document as “a method for a protected resource to query an OAuth 2.0 authorization server”,
and section 1 as a protocol that “allows authorized protected resources to query the
authorization server”. Through 0.9.1 this server had no channel for one: it
answered from a single arm, Some(t) if t.client_id == client.client_id, so a resource
server that did what the document told it to do was told, indistinguishably from the truth,
that every live token it held was dead. Advertising the endpoint unconditionally was
therefore the exact thing this module’s opening rule forbids: an advertised capability the
server rejects.
0.9.2 BUILT THE CHANNEL. A resource server declared in
crate::ServerConfig::resource_servers now authenticates as an ordinary confidential
client and is answered about the tokens addressed to it.
§Why this member stayed conditional anyway
0.9.1 recorded the intent that “when it lands this member becomes unconditional again”, and THAT INTENT IS DELIBERATELY NOT CARRIED OUT. Two reasons, and the second is the real one.
The cheap reason is that going back to String is itself a breaking change, so the API
would take two breaking changes in consecutive releases to arrive where it started, and the
second one would be paid by every host that had already adapted to the first.
The reason that actually decides it is that the capability is CONFIGURATION-DEPENDENT in a way 0.9.1 did not anticipate when it wrote that sentence. The resource-server channel is open only for a deployment that registered resource servers; one that registers none still answers the token’s own client and nobody else. Making the member unconditional would therefore restore the original defect precisely for the deployments the 0.9.1 change was made to protect – the endpoint would be advertised to resource servers that this particular deployment will never answer. The honest form of “advertise what you serve” is for the host, which is the only party that knows whether it configured any, to say so.
So: Option, and the host names the URL when it means the promise.
revocation_endpoint: Option<String>RFC 7009 section 2. Present when this server serves revocation.
registration_endpoint: Option<String>RFC 7591 section 3 / RFC 8414 section 2. Present ONLY when the host enabled dynamic client registration, and absent otherwise.
The conditional is the whole point of the member. RFC 8414 section 2 makes it optional, and a client reads its presence as “I may register here”; advertising it on a server that refuses every registration would be an endpoint that 404s or 401s for reasons a client cannot act on. The reverse is worse: RFC 7591 section 5 makes an unadvertised open endpoint no safer than an advertised one, so this must not become the thing a host relies on to keep registration private. It reports the configuration; it does not enforce it.
jwks_uri: Option<String>RFC 8414 section 2. With the jwt feature, present only when the server issues signed (JWT)
access tokens; an AS with opaque tokens has no keys to publish and must not pretend
otherwise.
WITHOUT that feature this crate signs nothing, so the member says only what
crate::server::ServerConfig::jwks_uri said: some other component holds the keys and
publishes them. Nothing in this crate serves that document, which is why the bundled http
service refuses to build when such a value points UNDER the issuer, where its own router
would answer the request with a 404.
scopes_supported: Option<Vec<String>>OPTIONAL (section 2). Omitted when the host has not declared a scope catalogue, since an empty array would claim the server supports no scopes at all.
par only.RFC 9126 section 5. Present ONLY when the host enabled PAR
(crate::server::ServerConfig::par): section 5 says its presence is sufficient for a
client to decide it may use PAR, so advertising an endpoint that is not served would be a
promise this server cannot keep.
par only.RFC 9126 section 5. Some(false) states the default explicitly when PAR is offered;
omitted entirely when PAR is off, since section 5 gives an absent member the meaning
false and a server with no PAR endpoint has nothing to require.
request_object_signing_alg_values_supported: Option<Vec<String>>jar only.RFC 9101 section 4: the alg values this server will verify a request object with.
Present only when signed request objects are enabled.
require_signed_request_object: Option<bool>jar only.RFC 9101 section 10.5, registered by its section 9.2. Present only when signed request
objects are enabled; true means a plain RFC 6749 authorization request is refused, which
is the downgrade that section describes.
response_types_supported: Vec<String>REQUIRED (section 2). Always exactly ["code"]: OAuth 2.1 removes the implicit grant.
response_modes_supported: Vec<String>OPTIONAL (section 2). This server returns the code in the query string.
grant_types_supported: Vec<String>OPTIONAL (section 2), and worth stating: it is how a client learns the device grant is available without probing.
token_endpoint_auth_methods_supported: Vec<String>OPTIONAL (section 2). Exactly the methods the token endpoint accepts.
token_endpoint_auth_signing_alg_values_supported: Option<Vec<String>>RFC 8414 section 2. The signing algorithms the token endpoint accepts on an RFC 7523 client assertion.
Section 2 makes this REQUIRED whenever token_endpoint_auth_methods_supported contains
client_secret_jwt or private_key_jwt, and the requirement is not bureaucratic: a client
cannot construct an assertion at all without knowing which algorithm the server will accept,
and guessing wrong is indistinguishable from a wrong key. Absent when this build does not
have the client-assertion feature, in which case neither method is advertised either.
dpop_signing_alg_values_supported: Option<Vec<String>>RFC 9449 section 5.1: the JWS algorithms this server will verify a DPoP proof under.
Its PRESENCE is how a client learns DPoP is available here at all, so it appears only when this build can actually verify a proof. Advertising it on a server that would refuse every proof is worse than omitting it, because a client that acts on it has no way to discover the mistake except by failing to get a token.
code_challenge_methods_supported: Vec<String>RFC 7636 / RFC 8414 section 2. Always exactly ["S256"]: plain is not implemented, and
advertising it would invite a downgrade this server cannot honor.
service_documentation: Option<String>OPTIONAL (section 2). A page of human-readable developer documentation.
protected_resources: Option<Vec<String>>resource-metadata only.RFC 9728 section 4. The resource identifiers of the protected resources this AS
issues tokens for, so a client that fetched a resource’s own RFC 9728 document can
cross-check that the AS agrees the relationship exists (section 7.6: an
authorization_servers entry is a claim made by the RESOURCE, and believing it
unchecked is how a resource points clients at an AS that never heard of it).
OPTIONAL, and omitted rather than empty when the host declared none: an empty array would state that this AS protects nothing, which is a different claim from silence.
rar only.RFC 9396 section 10. The authorization details TYPES this server will accept, so a client learns what it may ask for rather than discovering it from a refusal.
Omitted rather than empty when the host declared none, exactly as scopes_supported
is: an empty array claims the server supports no types at all, which is a different
statement from silence and would be read as one. Note that the SERVER’s behaviour for
the two is not different: an undeclared catalogue refuses every type (section 5), so
this member never overstates what the server will do.
client_id_metadata_document_supported: boolcimd only.draft-ietf-oauth-client-id-metadata-document-01 section 5 (section 6 in -02; see
crate::cimd for the renumbering). Whether this server dereferences an HTTPS URL used as
a client_id.
DERIVED FROM ServerConfig::cimd, never from the cargo feature. The feature compiles the
VALIDATOR in; it does not perform the fetch, because this crate performs no fetch at all
(see crate::cimd). So the only party who can answer this honestly is the host that
either wired the fetch or did not, and a member derived from #[cfg] would advertise a
capability a build might always refuse. Section 5’s default when the member is absent is
false, and this publishes false explicitly rather than omitting it, because the member
is what a client checks before trying at all.
RFC 9207 section 3. Always true from this server, and NOT an Option.
The member exists so a client can decide whether it is allowed to REQUIRE the iss
authorization response parameter, which is the mix-up countermeasure RFC 9700 section 4.4
names. RFC 9207 section 3 says its default when absent is false, so omitting it would tell
every client that the countermeasure is unavailable here even though this server always
sends the parameter. Publishing a constant true is only honest because
crate::authorization::AuthorizationResponse and
crate::authorization::AuthorizationErrorRedirect both carry iss unconditionally: the
claim and the behaviour cannot drift apart, because neither type can express its absence.
RFC 8707 (resource indicators), which this server also implements, registers NO metadata member of its own, so there is deliberately nothing here to advertise it.
#[serde(default)] on the way IN, and it is not a contradiction of the constant true on
the way out. Serialization is this server describing itself; deserialization is this type
reading someone else’s document, and section 3 makes the member OPTIONAL there with a
default of false. Without the attribute a bool field is a REQUIRED member to serde, so
this type could not parse the document of any AS that omits it, which is every AS that does
not implement RFC 9207. false is also the fail-closed reading: a client that cannot see
the promise must not require the parameter.
tls_client_certificate_bound_access_tokens: boolmtls only.RFC 8705 section 3.3. Always true in a build with the mtls feature, and absent
entirely without it, which is the same honesty rule jwks_uri follows.
Constant rather than configurable because the CODE PATH is: with the feature compiled in,
an access token issued for a request whose certificate the host passed in through
crate::server::ClientCredential::certificate is ALWAYS bound to it (RFC 8705 section 3).
There is no ServerConfig field that turns that off. Section 3.3’s default when the member
is absent is false, so a build without the feature says nothing and means nothing, which
is correct.
READ WHAT THE MEMBER THEREFORE MEANS, because it is narrower than it looks and the gap is
reachable. It says this server BINDS a certificate it is given; it does not and cannot say
that every token this deployment issues is bound, because whether a certificate arrives at
all is the host’s affair. This crate never terminates TLS. In particular the bundled http
feature’s router is handed an already-parsed request and passes certificate: None on every
credential it builds (see the comment on Credentials::credential in crate::http), so a
deployment whose only front door is that router publishes true here and binds nothing. A
host offering RFC 8705 has to reach the server through its own handler with the certificate
its terminator verified; a host that is not doing that should not compile the mtls feature
in, because this member is the promise a client acts on when it decides to present one.
#[serde(default)] for the reason its neighbour above carries one, and the case is not
hypothetical here: a build WITHOUT this feature omits the member entirely, so an mtls
build reading a non-mtls build’s own document failed outright with missing field "tls_client_certificate_bound_access_tokens" until 0.9.1. Section 3.3’s absent-means-false
is both the RFC’s answer and the fail-closed one: a client that cannot see the promise must
not assume its token is bound.
Implementations§
Source§impl AuthorizationServerMetadata
impl AuthorizationServerMetadata
Sourcepub fn from_config(config: &ServerConfig) -> Self
pub fn from_config(config: &ServerConfig) -> Self
Derive the document from the server’s configuration.
Endpoints the host did not override default to conventional paths under the issuer, so a host that configures only an issuer still publishes a coherent, self-consistent document.
Trait Implementations§
Source§impl Clone for AuthorizationServerMetadata
impl Clone for AuthorizationServerMetadata
Source§fn clone(&self) -> AuthorizationServerMetadata
fn clone(&self) -> AuthorizationServerMetadata
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more