You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-07-29 22:01:14 +03:00
Improve docs and spec compliance of oauth2-types requests
This commit is contained in:
committed by
Quentin Gliech
parent
bffbf63992
commit
7b281f4c21
@ -31,6 +31,10 @@ use crate::scope::Scope;
|
||||
|
||||
// ref: https://www.iana.org/assignments/oauth-parameters/oauth-parameters.xhtml
|
||||
|
||||
/// The mechanism to be used for returning Authorization Response parameters
|
||||
/// from the Authorization Endpoint.
|
||||
///
|
||||
/// Defined in [OAuth 2.0 Multiple Response Type Encoding Practices](https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#ResponseModes).
|
||||
#[derive(
|
||||
Debug,
|
||||
Hash,
|
||||
@ -47,11 +51,28 @@ use crate::scope::Scope;
|
||||
)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum ResponseMode {
|
||||
/// Authorization Response parameters are encoded in the query string added
|
||||
/// to the `redirect_uri`.
|
||||
Query,
|
||||
|
||||
/// Authorization Response parameters are encoded in the fragment added to
|
||||
/// the `redirect_uri`.
|
||||
Fragment,
|
||||
|
||||
/// Authorization Response parameters are encoded as HTML form values that
|
||||
/// are auto-submitted in the User Agent, and thus are transmitted via the
|
||||
/// HTTP `POST` method to the Client, with the result parameters being
|
||||
/// encoded in the body using the `application/x-www-form-urlencoded`
|
||||
/// format.
|
||||
///
|
||||
/// Defined in [OAuth 2.0 Form Post Response Mode](https://openid.net/specs/oauth-v2-form-post-response-mode-1_0.html).
|
||||
FormPost,
|
||||
}
|
||||
|
||||
/// Value that specifies how the Authorization Server displays the
|
||||
/// authentication and consent user interface pages to the End-User.
|
||||
///
|
||||
/// Defined in [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest).
|
||||
#[derive(
|
||||
Debug,
|
||||
Hash,
|
||||
@ -68,12 +89,35 @@ pub enum ResponseMode {
|
||||
)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum Display {
|
||||
/// The Authorization Server should display the authentication and consent
|
||||
/// UI consistent with a full User Agent page view.
|
||||
///
|
||||
/// This is the default display mode.
|
||||
Page,
|
||||
|
||||
/// The Authorization Server should display the authentication and consent
|
||||
/// UI consistent with a popup User Agent window.
|
||||
Popup,
|
||||
|
||||
/// The Authorization Server should display the authentication and consent
|
||||
/// UI consistent with a device that leverages a touch interface.
|
||||
Touch,
|
||||
|
||||
/// The Authorization Server should display the authentication and consent
|
||||
/// UI consistent with a "feature phone" type display.
|
||||
Wap,
|
||||
}
|
||||
|
||||
impl Default for Display {
|
||||
fn default() -> Self {
|
||||
Self::Page
|
||||
}
|
||||
}
|
||||
|
||||
/// Value that specifies whether the Authorization Server prompts the End-User
|
||||
/// for reauthentication and consent.
|
||||
///
|
||||
/// Defined in [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest).
|
||||
#[derive(
|
||||
Debug,
|
||||
Hash,
|
||||
@ -91,55 +135,130 @@ pub enum Display {
|
||||
#[display(style = "snake_case")]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum Prompt {
|
||||
/// The Authorization Server must not display any authentication or consent
|
||||
/// user interface pages.
|
||||
None,
|
||||
|
||||
/// The Authorization Server should prompt the End-User for
|
||||
/// reauthentication.
|
||||
Login,
|
||||
|
||||
/// The Authorization Server should prompt the End-User for consent before
|
||||
/// returning information to the Client.
|
||||
Consent,
|
||||
|
||||
/// The Authorization Server should prompt the End-User to select a user
|
||||
/// account.
|
||||
///
|
||||
/// This enables an End-User who has multiple accounts at the Authorization
|
||||
/// Server to select amongst the multiple accounts that they might have
|
||||
/// current sessions for.
|
||||
SelectAccount,
|
||||
|
||||
/// The Authorization Server should prompt the End-User to create a user
|
||||
/// account.
|
||||
///
|
||||
/// Defined in [Initiating User Registration via OpenID Connect](https://openid.net/specs/openid-connect-prompt-create-1_0.html).
|
||||
Create,
|
||||
}
|
||||
|
||||
/// The body of a request to the [Authorization Endpoint].
|
||||
///
|
||||
/// [Authorization Endpoint]: https://www.rfc-editor.org/rfc/rfc6749.html#section-3.1
|
||||
#[skip_serializing_none]
|
||||
#[serde_as]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct AuthorizationRequest {
|
||||
/// OAuth 2.0 Response Type value that determines the authorization
|
||||
/// processing flow to be used.
|
||||
pub response_type: OAuthAuthorizationEndpointResponseType,
|
||||
|
||||
/// OAuth 2.0 Client Identifier valid at the Authorization Server.
|
||||
pub client_id: String,
|
||||
|
||||
/// Redirection URI to which the response will be sent.
|
||||
///
|
||||
/// This field is required when using a response type returning an
|
||||
/// authorization code.
|
||||
///
|
||||
/// This URI must have been pre-registered with the OpenID Provider.
|
||||
pub redirect_uri: Option<Url>,
|
||||
|
||||
/// The scope of the access request.
|
||||
///
|
||||
/// OpenID Connect requests must contain the `openid` scope value.
|
||||
pub scope: Scope,
|
||||
|
||||
/// Opaque value used to maintain state between the request and the
|
||||
/// callback.
|
||||
pub state: Option<String>,
|
||||
|
||||
/// The mechanism to be used for returning parameters from the Authorization
|
||||
/// Endpoint.
|
||||
///
|
||||
/// This use of this parameter is not recommended when the Response Mode
|
||||
/// that would be requested is the default mode specified for the Response
|
||||
/// Type.
|
||||
pub response_mode: Option<ResponseMode>,
|
||||
|
||||
/// String value used to associate a Client session with an ID Token, and to
|
||||
/// mitigate replay attacks.
|
||||
pub nonce: Option<String>,
|
||||
|
||||
/// How the Authorization Server should display the authentication and
|
||||
/// consent user interface pages to the End-User.
|
||||
pub display: Option<Display>,
|
||||
|
||||
pub prompt: Option<Prompt>,
|
||||
/// Whether the Authorization Server should prompt the End-User for
|
||||
/// reauthentication and consent.
|
||||
///
|
||||
/// If [`Prompt::None`] is used, it must be the only value.
|
||||
#[serde_as(as = "Option<StringWithSeparator::<SpaceSeparator, Prompt>>")]
|
||||
#[serde(default)]
|
||||
pub prompt: Option<Vec<Prompt>>,
|
||||
|
||||
/// The allowable elapsed time in seconds since the last time the End-User
|
||||
/// was actively authenticated by the OpenID Provider.
|
||||
#[serde(default)]
|
||||
#[serde_as(as = "Option<DisplayFromStr>")]
|
||||
pub max_age: Option<NonZeroU32>,
|
||||
|
||||
/// End-User's preferred languages and scripts for the user interface.
|
||||
#[serde_as(as = "Option<StringWithSeparator::<SpaceSeparator, LanguageTag>>")]
|
||||
#[serde(default)]
|
||||
pub ui_locales: Option<Vec<LanguageTag>>,
|
||||
|
||||
/// ID Token previously issued by the Authorization Server being passed as a
|
||||
/// hint about the End-User's current or past authenticated session with the
|
||||
/// Client.
|
||||
pub id_token_hint: Option<String>,
|
||||
|
||||
/// Hint to the Authorization Server about the login identifier the End-User
|
||||
/// might use to log in.
|
||||
pub login_hint: Option<String>,
|
||||
|
||||
/// Requested Authentication Context Class Reference values.
|
||||
#[serde_as(as = "Option<StringWithSeparator::<SpaceSeparator, String>>")]
|
||||
#[serde(default)]
|
||||
pub acr_values: Option<HashSet<String>>,
|
||||
|
||||
/// A JWT that contains the request's parameter values, called a [Request
|
||||
/// Object].
|
||||
///
|
||||
/// [Request Object]: https://openid.net/specs/openid-connect-core-1_0.html#RequestObject
|
||||
pub request: Option<String>,
|
||||
|
||||
/// A URI referencing a [Request Object] or a [Pushed Authorization
|
||||
/// Request].
|
||||
///
|
||||
/// [Request Object]: https://openid.net/specs/openid-connect-core-1_0.html#RequestUriParameter
|
||||
/// [Pushed Authorization Request]: https://datatracker.ietf.org/doc/html/rfc9126
|
||||
pub request_uri: Option<Url>,
|
||||
|
||||
/// A JSON object containing the Client Metadata when interacting with a
|
||||
/// [Self-Issued OpenID Provider].
|
||||
///
|
||||
/// [Self-Issued OpenID Provider]: https://openid.net/specs/openid-connect-core-1_0.html#SelfIssued
|
||||
pub registration: Option<String>,
|
||||
}
|
||||
|
||||
@ -173,6 +292,9 @@ impl AuthorizationRequest {
|
||||
}
|
||||
}
|
||||
|
||||
/// A successful response from the [Authorization Endpoint].
|
||||
///
|
||||
/// [Authorization Endpoint]: https://www.rfc-editor.org/rfc/rfc6749.html#section-3.1
|
||||
#[skip_serializing_none]
|
||||
#[derive(Serialize, Deserialize, Default, Debug, Clone)]
|
||||
pub struct AuthorizationResponse<R> {
|
||||
@ -181,33 +303,58 @@ pub struct AuthorizationResponse<R> {
|
||||
pub response: R,
|
||||
}
|
||||
|
||||
/// A request to the [Token Endpoint] for the [Authorization Code] grant type.
|
||||
///
|
||||
/// [Token Endpoint]: https://www.rfc-editor.org/rfc/rfc6749#section-3.2
|
||||
/// [Authorization Code]: https://www.rfc-editor.org/rfc/rfc6749#section-4.1
|
||||
#[skip_serializing_none]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||
pub struct AuthorizationCodeGrant {
|
||||
/// The authorization code that was returned from the authorization
|
||||
/// endpoint.
|
||||
pub code: String,
|
||||
#[serde(default)]
|
||||
|
||||
/// The `redirect_uri` that was included in the authorization request.
|
||||
///
|
||||
/// This field must match exactly the value passed to the authorization
|
||||
/// endpoint.
|
||||
pub redirect_uri: Option<Url>,
|
||||
|
||||
/// The code verifier that matches the code challenge that was sent to the
|
||||
/// authorization endpoint.
|
||||
// TODO: move this somehow in the pkce module
|
||||
#[serde(default)]
|
||||
pub code_verifier: Option<String>,
|
||||
}
|
||||
|
||||
/// A request to the [Token Endpoint] for [refreshing an access token].
|
||||
///
|
||||
/// [Token Endpoint]: https://www.rfc-editor.org/rfc/rfc6749#section-3.2
|
||||
/// [refreshing an access token]: https://www.rfc-editor.org/rfc/rfc6749#section-6
|
||||
#[skip_serializing_none]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||
pub struct RefreshTokenGrant {
|
||||
/// The refresh token issued to the client.
|
||||
pub refresh_token: String,
|
||||
|
||||
#[serde(default)]
|
||||
/// The scope of the access request.
|
||||
///
|
||||
/// The requested scope must not include any scope not originally granted by
|
||||
/// the resource owner, and if omitted is treated as equal to the scope
|
||||
/// originally granted by the resource owner.
|
||||
pub scope: Option<Scope>,
|
||||
}
|
||||
|
||||
/// A request to the [Token Endpoint] for the [Client Credentials] grant type.
|
||||
///
|
||||
/// [Token Endpoint]: https://www.rfc-editor.org/rfc/rfc6749#section-3.2
|
||||
/// [Client Credentials]: https://www.rfc-editor.org/rfc/rfc6749#section-4.4
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ClientCredentialsGrant {
|
||||
#[serde(default)]
|
||||
/// The scope of the access request.
|
||||
pub scope: Option<Scope>,
|
||||
}
|
||||
|
||||
/// All possible values for the `grant_type` parameter.
|
||||
#[derive(
|
||||
Debug,
|
||||
Hash,
|
||||
@ -224,40 +371,62 @@ pub struct ClientCredentialsGrant {
|
||||
)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum GrantType {
|
||||
/// [`authorization_code`](https://www.rfc-editor.org/rfc/rfc6749#section-4.1)
|
||||
AuthorizationCode,
|
||||
|
||||
/// [`refresh_token`](https://www.rfc-editor.org/rfc/rfc6749#section-6)
|
||||
RefreshToken,
|
||||
|
||||
/// [`implicit`](https://www.rfc-editor.org/rfc/rfc6749#section-4.2)
|
||||
Implicit,
|
||||
|
||||
/// [`client_credentials`](https://www.rfc-editor.org/rfc/rfc6749#section-4.4)
|
||||
ClientCredentials,
|
||||
}
|
||||
|
||||
/// An enum representing the possible requests to the [Token Endpoint].
|
||||
///
|
||||
/// [Token Endpoint]: https://www.rfc-editor.org/rfc/rfc6749#section-3.2
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||
#[serde(tag = "grant_type", rename_all = "snake_case")]
|
||||
pub enum AccessTokenRequest {
|
||||
AuthorizationCode(AuthorizationCodeGrant),
|
||||
RefreshToken(RefreshTokenGrant),
|
||||
ClientCredentials(ClientCredentialsGrant),
|
||||
#[serde(skip_deserializing, other)]
|
||||
#[serde(skip, other)]
|
||||
Unsupported,
|
||||
}
|
||||
|
||||
/// A successful response from the [Token Endpoint].
|
||||
///
|
||||
/// [Token Endpoint]: https://www.rfc-editor.org/rfc/rfc6749#section-3.2
|
||||
#[serde_as]
|
||||
#[skip_serializing_none]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||
pub struct AccessTokenResponse {
|
||||
/// The access token to access the requested scope.
|
||||
pub access_token: String,
|
||||
|
||||
/// The token to refresh the access token when it expires.
|
||||
pub refresh_token: Option<String>,
|
||||
|
||||
/// ID Token value associated with the authenticated session.
|
||||
// TODO: this should be somewhere else
|
||||
pub id_token: Option<String>,
|
||||
|
||||
/// The type of the access token.
|
||||
pub token_type: OAuthAccessTokenType,
|
||||
|
||||
/// The duration for which the access token is valid.
|
||||
#[serde_as(as = "Option<DurationSeconds<i64>>")]
|
||||
pub expires_in: Option<Duration>,
|
||||
|
||||
/// The scope of the access token.
|
||||
pub scope: Option<Scope>,
|
||||
}
|
||||
|
||||
impl AccessTokenResponse {
|
||||
/// Creates a new `AccessTokenResponse` with the given access token.
|
||||
#[must_use]
|
||||
pub fn new(access_token: String) -> AccessTokenResponse {
|
||||
AccessTokenResponse {
|
||||
@ -270,24 +439,28 @@ impl AccessTokenResponse {
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds a refresh token to an `AccessTokenResponse`.
|
||||
#[must_use]
|
||||
pub fn with_refresh_token(mut self, refresh_token: String) -> Self {
|
||||
self.refresh_token = Some(refresh_token);
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds an ID token to an `AccessTokenResponse`.
|
||||
#[must_use]
|
||||
pub fn with_id_token(mut self, id_token: String) -> Self {
|
||||
self.id_token = Some(id_token);
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds a scope to an `AccessTokenResponse`.
|
||||
#[must_use]
|
||||
pub fn with_scope(mut self, scope: Scope) -> Self {
|
||||
self.scope = Some(scope);
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds an expiration duration to an `AccessTokenResponse`.
|
||||
#[must_use]
|
||||
pub fn with_expires_in(mut self, expires_in: Duration) -> Self {
|
||||
self.expires_in = Some(expires_in);
|
||||
@ -295,44 +468,64 @@ impl AccessTokenResponse {
|
||||
}
|
||||
}
|
||||
|
||||
/// A request to the [Introspection Endpoint].
|
||||
///
|
||||
/// [Introspection Endpoint]: https://www.rfc-editor.org/rfc/rfc7662#section-2
|
||||
#[skip_serializing_none]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||
pub struct IntrospectionRequest {
|
||||
/// The value of the token.
|
||||
pub token: String,
|
||||
|
||||
#[serde(default)]
|
||||
/// A hint about the type of the token submitted for introspection.
|
||||
pub token_type_hint: Option<OAuthTokenTypeHint>,
|
||||
}
|
||||
|
||||
/// A successful response from the [Introspection Endpoint].
|
||||
///
|
||||
/// [Introspection Endpoint]: https://www.rfc-editor.org/rfc/rfc7662#section-2
|
||||
#[serde_as]
|
||||
#[skip_serializing_none]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)]
|
||||
pub struct IntrospectionResponse {
|
||||
/// Whether or not the presented token is currently active.
|
||||
pub active: bool,
|
||||
|
||||
/// The scope associated with the token.
|
||||
pub scope: Option<Scope>,
|
||||
|
||||
/// Client identifier for the OAuth 2.0 client that requested this token.
|
||||
pub client_id: Option<String>,
|
||||
|
||||
/// Human-readable identifier for the resource owner who authorized this
|
||||
/// token.
|
||||
pub username: Option<String>,
|
||||
|
||||
/// Type of the token.
|
||||
pub token_type: Option<OAuthTokenTypeHint>,
|
||||
|
||||
/// Timestamp indicating when the token will expire.
|
||||
#[serde_as(as = "Option<TimestampSeconds>")]
|
||||
pub exp: Option<DateTime<Utc>>,
|
||||
|
||||
/// Timestamp indicating when the token was issued.
|
||||
#[serde_as(as = "Option<TimestampSeconds>")]
|
||||
pub iat: Option<DateTime<Utc>>,
|
||||
|
||||
/// Timestamp indicating when the token is not to be used before.
|
||||
#[serde_as(as = "Option<TimestampSeconds>")]
|
||||
pub nbf: Option<DateTime<Utc>>,
|
||||
|
||||
/// Subject of the token.
|
||||
pub sub: Option<String>,
|
||||
|
||||
/// Intended audience of the token.
|
||||
pub aud: Option<String>,
|
||||
|
||||
/// Issuer of the token.
|
||||
pub iss: Option<String>,
|
||||
|
||||
/// String identifier for the token.
|
||||
pub jti: Option<String>,
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user