pub struct DeviceAuth { /* private fields */ }Expand description
The device authorization grant (RFC 8628) over the harness’s own ports.
Implementations§
Source§impl DeviceAuth
impl DeviceAuth
Sourcepub fn builder() -> DeviceAuthBuilder
pub fn builder() -> DeviceAuthBuilder
A builder with no clients, no hooks and the RFC 8628 defaults. It
is not a working composition until .client(..), .issuer(..) and
.random(..) are set; Module::self_check names what is missing.
Sourcepub fn new() -> Self
pub fn new() -> Self
Short for DeviceAuth::builder().build().
Trait Implementations§
Source§impl Default for DeviceAuth
impl Default for DeviceAuth
Source§impl Module for DeviceAuth
impl Module for DeviceAuth
Source§fn requires(&self) -> &'static [Port]
fn requires(&self) -> &'static [Port]
The codes live in the database, and the polling route is public: the limiter is the abuse control it actually has. Both are requirements rather than options — a deployment without a limiter mounted would serve an unthrottled public poll endpoint, which is what production readiness exists to refuse (issue #562).
Source§fn optional(&self) -> &'static [Port]
fn optional(&self) -> &'static [Port]
The Clock decides “now” for expiry and the poll interval. The Auth
port is what the stock CallerApprover identifies callers with;
a deployment that builds its own approver does not need it, so it
is optional rather than required.
Source§fn personal_data(&self) -> &'static [PersonalDataSet]
fn personal_data(&self) -> &'static [PersonalDataSet]
One row per request, and the row is the approver’s: it names who
approved the device (approver_subject) and carries the label the
client put on it (name, which is whatever the client chose to
call the device — “Alice’s laptop”).
The codes themselves are stored only as hashes and are not the
subject: a device_code is a bearer credential with no person
behind it, and a user_code is eight letters off a screen. The
subject is the person who pressed Approve, and an erasure request
that names them deletes the row.
Source§fn validate_config(&self, _cfg: &dyn Config) -> Result<(), ConfigError>
fn validate_config(&self, _cfg: &dyn Config) -> Result<(), ConfigError>
No configuration keys of its own: the composition is what a
venture decides, and self_check reports a composition that cannot
serve a device sign-in.
Source§fn self_check(&self) -> Vec<String>
fn self_check(&self) -> Vec<String>
The composition a build must refuse. A device grant with no clients
can authorize nobody; one with no issuer mints nothing; one with no
entropy source cannot draw a code. Reported here rather than in
validate_config because none of it comes from the environment —
it is what the venture composed, and the fix is in the composition.
Source§fn surface(&self) -> Surface
fn surface(&self) -> Surface
The two machine routes, the browser page and the two decision forms.
All four writes are RoutePolicy::Open, and deliberately so.
/code and /token are called by a program, so a CAPTCHA is
meaningless and a signed link would demand a Signer key ring this
module never issues from — their proof is the single-use
device_code the module itself minted, and their abuse control is
the RateLimiter the module requires (plus the poll interval
/token enforces). /approve and /deny are the browser’s, and
the handler authenticates them itself: they need a signed-in
approver, which is Audience::Subject here, and the same-origin
check runs before the body is trusted.
Source§fn scheduled<'a>(
&'a self,
ctx: &'a ModuleContext,
cron: &'a str,
) -> BoxFuture<'a, Result<(), AnyError>>
fn scheduled<'a>( &'a self, ctx: &'a ModuleContext, cron: &'a str, ) -> BoxFuture<'a, Result<(), AnyError>>
The scheduled purge: rows past their expiry are deleted, because
an expired code is useless to both sides — the client is told
expired_token and the approver is told the code is gone. One
statement, so it spends one unit of the invocation’s budget (ADR
0023) and leaves the rest to the modules behind it.
Source§fn tables(&self) -> &'static [&'static str]
fn tables(&self) -> &'static [&'static str]
Source§fn migrations(&self) -> Migrations
fn migrations(&self) -> Migrations
Source§fn router(&self, ctx: ModuleContext) -> Router
fn router(&self, ctx: ModuleContext) -> Router
/v1/<name>.Source§fn harness_api(&self) -> u32
fn harness_api(&self) -> u32
Harness::build.Source§fn depends_on(&self) -> &'static [&'static str]
fn depends_on(&self) -> &'static [&'static str]
Source§fn emits(&self) -> &'static [&'static str]
fn emits(&self) -> &'static [&'static str]
"<module>.<event>"), listed by
/__health.Source§fn public_writes(&self) -> bool
fn public_writes(&self) -> bool
Source§fn public_write_policy(&self) -> RoutePolicy
fn public_write_policy(&self) -> RoutePolicy
RoutePolicy on
(issue #143). Read moreSource§fn signature_verification(&self) -> SignatureVerification
fn signature_verification(&self) -> SignatureVerification
RoutePolicy::Signature
deliveries (issue #533): how a webhook handler checks a machine
signature before acting. Read moreSource§fn max_body_bytes(&self, _cfg: &dyn Config) -> usize
fn max_body_bytes(&self, _cfg: &dyn Config) -> usize
Source§fn streaming_routes(&self) -> &'static [StreamRoute]
fn streaming_routes(&self) -> &'static [StreamRoute]
StreamRoute::max_bytes ceiling. Opt-in: the default
is empty, and every existing route keeps the buffered behaviour it
always had. Read moreSource§fn well_known(&self) -> Option<Router>
fn well_known(&self) -> Option<Router>
/.well-known, for
spec-mandated discovery documents (OIDC openid-configuration,
jwks.json) that must live outside /v1 (issue #46). Paths are
relative to the prefix: register /jwks.json, not
/.well-known/jwks.json. Read more