Skip to main content

AuthorizationCodeRecord

Struct AuthorizationCodeRecord 

Source
#[non_exhaustive]
pub struct AuthorizationCodeRecord {
Show 14 fields pub code: String, pub client_id: ClientId, pub redirect_uri: String, pub redirect_uri_was_explicit: bool, pub scope: ScopeSet, pub subject: String, pub code_challenge: String, pub code_challenge_method: CodeChallengeMethod, pub resource: Vec<String>, pub authorization_details: AuthorizationDetails, pub issued_at: SystemTime, pub expires_at: SystemTime, pub state: AuthorizationCodeState, pub authentication: Option<Box<Authentication>>,
}
Expand description

A persisted authorization code (RFC 6749 section 4.1.2).

Debug is hand-written (see below): code is itself a bearer credential (RFC 6749 section 4.1.2 treats a leaked code as equivalent to a leaked token for as long as it is live, which is why replay revokes what it minted, see AuthorizationCodeState’s doc comment), so it must not appear in a debug format either. #[non_exhaustive]: rar and consent each add a field. Like the two token records this is a value a crate::store::Storage implementor is HANDED and gives back, through the derived serde impls, which are generated in this crate and keep working from outside it; nothing in oauth-as-postgres names a field of it. AuthorizationCodeRecord::new is for anyone building one directly.

Fields (Non-exhaustive)§

This struct is marked as non-exhaustive
Non-exhaustive structs could have additional fields added in future. Therefore, non-exhaustive structs cannot be constructed in external crates using the traditional Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.
§code: String

The code string (the storage key).

§client_id: ClientId

The client the code was issued to; presentation by any other client is invalid_grant.

§redirect_uri: String

The redirect URI the authorization request used; a token request that presents one must present this one.

§redirect_uri_was_explicit: bool

Whether the authorization request NAMED that URI, rather than omitting it and being filled in from the client’s single registration (RFC 6749 section 3.1.2.3).

RFC 6749 section 4.1.3 makes the token endpoint’s redirect_uri parameter REQUIRED “if the redirect_uri parameter was included in the authorization request”, and conditional means conditional in both directions: through 0.9.1 the token endpoint required it always, so a client entitled by section 3.1.2.3 to omit it at the authorization endpoint — the ordinary shape for a client with exactly one registered URI — was refused at the token endpoint, and refused with a message blaming a mismatch that had not happened. redirect_uri above cannot stand in for this, because it is filled in either way.

#[serde(default)] with a true default, so a record persisted by 0.9.0 still deserializes. TRUE is the fail-closed direction: it keeps the check that release performed (the parameter is required) for records minted before this field existed, rather than silently waiving section 4.1.3’s requirement for every grant that survived the upgrade.

§scope: ScopeSet

The scope the user approved.

§subject: String

The authenticated resource owner.

§code_challenge: String

The recorded PKCE challenge (RFC 7636 section 4.4).

§code_challenge_method: CodeChallengeMethod

The recorded PKCE method.

§resource: Vec<String>

The RFC 8707 resource indicators the authorization request named.

Recorded on the code because the token request that redeems it MAY narrow this set but MUST NOT widen it (RFC 8707 section 2), and “what was granted” is not knowable at the token endpoint any other way. Empty means the client asked for no audience restriction.

§authorization_details: AuthorizationDetails
Available on crate feature rar only.

The RFC 9396 authorization details the user approved.

Recorded on the code for exactly the reason resource above is: section 6 lets the token request that redeems it NARROW this set and never widen it, and “what was granted” is not knowable at the token endpoint any other way. Empty means the client asked for no rich authorization detail.

#[serde(default)], which crate::token::IssuedToken::authorization_details states in full: a code written by a build without rar carries no such key, this is not an Option so serde supplies no default of its own, and without one every code in flight becomes unreadable the moment anything in the host’s dependency graph turns the feature on.

§issued_at: SystemTime

The instant this code was MINTED, which is the instant the user’s authorization decision was made. Carried into crate::token::IssuedToken::grant_established_at on redemption so that a revocation can tell a code that predates it from one minted afterwards.

expires_at cannot stand in for this: a code minted a minute before a withdrawal expires minutes AFTER it, so comparing the deadline would let exactly the in-flight redemption a barrier exists to refuse through.

#[serde(default)], and the default is the epoch, which is the FAIL-CLOSED direction. This field is new in 0.9.1, so a code a 0.9.0 node wrote — or is still writing, during a rolling upgrade — carries no such key, and without a default the read fails outright and every code that release minted becomes unredeemable the moment this one starts. With it, the record deserializes and dates from before every barrier that could ever be recorded, so a standing revocation REFUSES it rather than admitting it. A far-future default would deserialize just as happily and ADMIT every code 0.9.0 wrote, which is exactly the resurrection this field exists to close, reintroduced through the upgrade path. The There is deliberately NO backfill migration: a backfill cannot reach a 0.9.0 node still writing field-less payloads during a rolling upgrade, which is the window that matters, so the serde default covers strictly more than one would.

§expires_at: SystemTime

Expiry instant; the code is dead at and after this instant.

§state: AuthorizationCodeState

Whether the code has been redeemed, and what it produced.

§authentication: Option<Box<Authentication>>
Available on crate feature consent only.

What the host reported about the resource owner’s authentication when this code was approved (the consent-0.8.0 slice; see crate::consent::Authentication).

Recorded on the CODE because that is the only path by which the authentication the user actually performed can reach the token the code mints: the token endpoint has no user in front of it and cannot ask. Without it, RFC 9470 section 6’s auth_time and acr could only ever be guessed at.

Implementations§

Source§

impl AuthorizationCodeRecord

Source

pub fn new( code: impl Into<String>, client_id: ClientId, redirect_uri: impl Into<String>, scope: ScopeSet, subject: impl Into<String>, code_challenge: impl Into<String>, expires_at: SystemTime, ) -> Self

A freshly minted, unredeemed code: state is AuthorizationCodeState::Issued, because the Consumed form records what a redemption produced and there is nothing to record until one happens.

Every argument is a value the record is worthless without, and each is one the RFC names as the thing a later token request is checked against: the redirect_uri it must present again (RFC 6749 section 4.1.3), the code_challenge it must produce a verifier for (RFC 7636 section 4.6), the subject and scope it is redeeming on behalf of, and the instant after which none of that is true any more. The method is S256 and not an argument, because CodeChallengeMethod has one variant and it is one for a reason.

Trait Implementations§

Source§

impl Clone for AuthorizationCodeRecord

Source§

fn clone(&self) -> AuthorizationCodeRecord

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for AuthorizationCodeRecord

Hand-written so the one-time code never prints (RFC 6749 section 4.1.2 makes it a credential in its own right). EVERY other field prints, on the rule crate::token::IssuedToken’s Debug states in full. issued_at in particular: it is what a crate::store::RevocationBarrier is compared against on redemption, its fail-closed default is the epoch, and without it printing an operator cannot tell a code refused by a standing barrier from one refused for any other reason.

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de> Deserialize<'de> for AuthorizationCodeRecord

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Eq for AuthorizationCodeRecord

Source§

impl PartialEq for AuthorizationCodeRecord

Source§

fn eq(&self, other: &AuthorizationCodeRecord) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl Serialize for AuthorizationCodeRecord

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl StructuralPartialEq for AuthorizationCodeRecord

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FromRef<T> for T
where T: Clone,

Source§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
Source§

impl<A, B, T> HttpServerConnExec<A, B> for T
where B: Body,

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.