pub struct ServiceBuilder<S: Storage, C: Clock> { /* private fields */ }http only.Expand description
Builds the router. Construct, attach the seams the interactive endpoints need, then
build.
§The interactive endpoints refuse until they are wired
with_subject_resolver alone is NOT enough to run an
authorization server safely, and this is the one thing to read in this file. It answers “who
is this user”; RFC 6749 s10.12 also demands “did the user knowingly agree”. Wire
with_approval_resolver and
with_csrf_tokens too, or the authorization endpoint and
the device verification form refuse rather than guessing that silence means yes.
Implementations§
Source§impl<S: Storage + 'static, C: Clock + 'static> ServiceBuilder<S, C>
impl<S: Storage + 'static, C: Clock + 'static> ServiceBuilder<S, C>
Sourcepub fn new(server: Arc<AuthorizationServer<S, C>>) -> Self
pub fn new(server: Arc<AuthorizationServer<S, C>>) -> Self
Start from a running server. Arc rather than ownership so the host keeps its handle for
administration (client registration, sweeping) while the router serves the same instance.
Sourcepub fn with_subject_resolver<F>(self, resolver: F) -> Self
pub fn with_subject_resolver<F>(self, resolver: F) -> Self
Supply the host’s answer to “who is the logged-in user for this request”.
The authorization endpoint cannot mint a code without a resource owner, and the device verification page cannot approve a grant without one. This crate has no login UI and no session model by design, so without a resolver both endpoints refuse with 403 rather than inventing a user.
This resolver is IDENTITY ONLY. It does not express approval; see
with_approval_resolver.
Sourcepub fn with_approval_resolver<F>(self, resolver: F) -> Self
pub fn with_approval_resolver<F>(self, resolver: F) -> Self
Supply the host’s answer to “has this user knowingly agreed to this exact request”.
RFC 6749 s10.12 requires the AS to “ensure that the malicious client cannot obtain authorization without the awareness and explicit consent of the resource owner”. An authorization endpoint that mints a code as soon as it knows who the user is satisfies neither half: any cross-site top-level navigation makes a logged-in user’s browser hand a registered client a code they never asked to issue. PKCE and exact redirect-URI matching bound WHO may redeem that code; they say nothing about whether it should have existed.
With NO resolver the authorization endpoint refuses with 403 and issues nothing. That is
deliberate and it is a behaviour change: a host that previously wired only
with_subject_resolver was running an
AUTO-APPROVING authorization server, and the fix is to say what the approval step is rather
than to leave it implied.
Return ApprovalDecision::Respond to render a consent screen and finish the flow on a
later request; return ApprovalDecision::Approve only once the user has actually agreed.
Sourcepub fn with_authentication_reporter<F>(self, reporter: F) -> Self
Available on crate feature consent only.
pub fn with_authentication_reporter<F>(self, reporter: F) -> Self
consent only.Supply the host’s answer to “when, and how, did you authenticate this user”.
REQUIRED for RFC 9470 step-up authentication and useless without it. A client answering a
resource server’s insufficient_user_authentication challenge repeats its authorization
request with acr_values and/or max_age; this server enforces those against whatever the
reporter returns, and a host with no reporter wired fails every such request. That is the
correct answer rather than a bug: an authorization server that cannot say when the user
logged in cannot honestly claim they logged in recently.
Ordinary requests, which carry neither parameter, are unaffected whether this is wired or not.
The report is taken at FACE VALUE. This crate cannot authenticate anyone and has nothing to
check it against; see the crate::consent module docs.
Sourcepub fn with_csrf_tokens<I, V>(self, issue: I, consume: V) -> Self
pub fn with_csrf_tokens<I, V>(self, issue: I, consume: V) -> Self
Supply the host’s session-bound CSRF token for the device verification form.
issue is called when the form is RENDERED: it mints a token, binds it to whatever
session the request carries, and returns it to be embedded in the form. consume is
called when the form is SUBMITTED: it returns the token that session was last issued AND
invalidates it, which is what makes the token single use. The router compares the
submitted token with the consumed one in constant time; a mismatch, or either hook
answering None, is a refusal.
Why this is a seam and not something the library does: approving a device grant binds a third party’s grant to the logged-in user, so RFC 6749 s10.12’s CSRF requirement applies with full force, and the countermeasure has to be bound to the SESSION. This crate has no session store and will not grow one. With no hooks the verification endpoint renders no form and approves nothing, because a form that works and is forgeable is worse than no form at all.
Sourcepub fn dangerously_disable_verification_protections(self) -> Self
pub fn dangerously_disable_verification_protections(self) -> Self
Turn OFF the device verification form’s CSRF token requirement, its Origin check, and
its affirmative-action requirement.
FOR NON-BROWSER TEST HARNESSES ONLY. On an endpoint a browser can reach this re-enables
the complete RFC 6749 s10.12 cross-site forced-approval chain: an attacker starts a device
grant for a client they control, gets any authenticated victim’s browser to POST the
user_code, and polls out an access token and a refresh token for the victim’s account.
That is account takeover, and it needs no interaction beyond loading a page.
It exists because this crate’s black-box conformance harness drives the verification endpoint with an HTTP client and no browser session, so it cannot hold a CSRF token. It is spelled this loudly so that it is greppable, and so that no production host reaches for it without having read what it does.
Sourcepub fn build(self) -> Result<AuthorizationService<S, C>, ServiceError>
pub fn build(self) -> Result<AuthorizationService<S, C>, ServiceError>
Derive the routes from the metadata document and build the service.
§Errors
ServiceError when the configuration advertises something this service cannot serve.