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
@ -193,6 +193,7 @@ pub(crate) async fn get(
|
|||||||
.load_session(&mut txn)
|
.load_session(&mut txn)
|
||||||
.await
|
.await
|
||||||
.context("failed to load browser session")?;
|
.context("failed to load browser session")?;
|
||||||
|
let prompt = params.auth.prompt.as_deref().unwrap_or_default();
|
||||||
|
|
||||||
// Check if the request/request_uri/registration params are used. If so, reply
|
// Check if the request/request_uri/registration params are used. If so, reply
|
||||||
// with the right error since we don't support them.
|
// with the right error since we don't support them.
|
||||||
@ -234,7 +235,7 @@ pub(crate) async fn get(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fail early if prompt=none and there is no active session
|
// Fail early if prompt=none and there is no active session
|
||||||
if params.auth.prompt == Some(Prompt::None) && maybe_session.is_none() {
|
if prompt.contains(&Prompt::None) && maybe_session.is_none() {
|
||||||
return Ok(callback_destination
|
return Ok(callback_destination
|
||||||
.go(
|
.go(
|
||||||
&templates,
|
&templates,
|
||||||
@ -272,7 +273,7 @@ pub(crate) async fn get(
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let requires_consent = params.auth.prompt == Some(Prompt::Consent);
|
let requires_consent = prompt.contains(&Prompt::Consent);
|
||||||
|
|
||||||
let grant = new_authorization_grant(
|
let grant = new_authorization_grant(
|
||||||
&mut txn,
|
&mut txn,
|
||||||
@ -292,13 +293,13 @@ pub(crate) async fn get(
|
|||||||
.await?;
|
.await?;
|
||||||
let continue_grant = PostAuthAction::continue_grant(grant.data);
|
let continue_grant = PostAuthAction::continue_grant(grant.data);
|
||||||
|
|
||||||
let res = match (maybe_session, params.auth.prompt) {
|
let res = match maybe_session {
|
||||||
// Cases where there is no active session, redirect to the relevant page
|
// Cases where there is no active session, redirect to the relevant page
|
||||||
(None, Some(Prompt::None)) => {
|
None if prompt.contains(&Prompt::None) => {
|
||||||
// This case should already be handled earlier
|
// This case should already be handled earlier
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
(None, Some(Prompt::Create)) => {
|
None if prompt.contains(&Prompt::Create) => {
|
||||||
// Client asked for a registration, show the registration prompt
|
// Client asked for a registration, show the registration prompt
|
||||||
txn.commit().await?;
|
txn.commit().await?;
|
||||||
|
|
||||||
@ -306,7 +307,7 @@ pub(crate) async fn get(
|
|||||||
.go()
|
.go()
|
||||||
.into_response()
|
.into_response()
|
||||||
}
|
}
|
||||||
(None, _) => {
|
None => {
|
||||||
// Other cases where we don't have a session, ask for a login
|
// Other cases where we don't have a session, ask for a login
|
||||||
txn.commit().await?;
|
txn.commit().await?;
|
||||||
|
|
||||||
@ -316,7 +317,10 @@ pub(crate) async fn get(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Special case when we already have a sesion but prompt=login|select_account
|
// Special case when we already have a sesion but prompt=login|select_account
|
||||||
(Some(_), Some(Prompt::Login | Prompt::SelectAccount)) => {
|
Some(_)
|
||||||
|
if prompt.contains(&Prompt::Login)
|
||||||
|
|| prompt.contains(&Prompt::SelectAccount) =>
|
||||||
|
{
|
||||||
// TODO: better pages here
|
// TODO: better pages here
|
||||||
txn.commit().await?;
|
txn.commit().await?;
|
||||||
|
|
||||||
@ -326,7 +330,7 @@ pub(crate) async fn get(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Else, we immediately try to complete the authorization grant
|
// Else, we immediately try to complete the authorization grant
|
||||||
(Some(user_session), Some(Prompt::None)) => {
|
Some(user_session) if prompt.contains(&Prompt::None) => {
|
||||||
// With prompt=none, we should get back to the client immediately
|
// With prompt=none, we should get back to the client immediately
|
||||||
match self::complete::complete(grant, user_session, &policy_factory, txn).await
|
match self::complete::complete(grant, user_session, &policy_factory, txn).await
|
||||||
{
|
{
|
||||||
@ -362,7 +366,7 @@ pub(crate) async fn get(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(Some(user_session), _) => {
|
Some(user_session) => {
|
||||||
let grant_id = grant.data;
|
let grant_id = grant.data;
|
||||||
// Else, we show the relevant reauth/consent page if necessary
|
// Else, we show the relevant reauth/consent page if necessary
|
||||||
match self::complete::complete(grant, user_session, &policy_factory, txn).await
|
match self::complete::complete(grant, user_session, &policy_factory, txn).await
|
||||||
|
@ -31,6 +31,10 @@ use crate::scope::Scope;
|
|||||||
|
|
||||||
// ref: https://www.iana.org/assignments/oauth-parameters/oauth-parameters.xhtml
|
// 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(
|
#[derive(
|
||||||
Debug,
|
Debug,
|
||||||
Hash,
|
Hash,
|
||||||
@ -47,11 +51,28 @@ use crate::scope::Scope;
|
|||||||
)]
|
)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum ResponseMode {
|
pub enum ResponseMode {
|
||||||
|
/// Authorization Response parameters are encoded in the query string added
|
||||||
|
/// to the `redirect_uri`.
|
||||||
Query,
|
Query,
|
||||||
|
|
||||||
|
/// Authorization Response parameters are encoded in the fragment added to
|
||||||
|
/// the `redirect_uri`.
|
||||||
Fragment,
|
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,
|
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(
|
#[derive(
|
||||||
Debug,
|
Debug,
|
||||||
Hash,
|
Hash,
|
||||||
@ -68,12 +89,35 @@ pub enum ResponseMode {
|
|||||||
)]
|
)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum Display {
|
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,
|
Page,
|
||||||
|
|
||||||
|
/// The Authorization Server should display the authentication and consent
|
||||||
|
/// UI consistent with a popup User Agent window.
|
||||||
Popup,
|
Popup,
|
||||||
|
|
||||||
|
/// The Authorization Server should display the authentication and consent
|
||||||
|
/// UI consistent with a device that leverages a touch interface.
|
||||||
Touch,
|
Touch,
|
||||||
|
|
||||||
|
/// The Authorization Server should display the authentication and consent
|
||||||
|
/// UI consistent with a "feature phone" type display.
|
||||||
Wap,
|
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(
|
#[derive(
|
||||||
Debug,
|
Debug,
|
||||||
Hash,
|
Hash,
|
||||||
@ -91,55 +135,130 @@ pub enum Display {
|
|||||||
#[display(style = "snake_case")]
|
#[display(style = "snake_case")]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum Prompt {
|
pub enum Prompt {
|
||||||
|
/// The Authorization Server must not display any authentication or consent
|
||||||
|
/// user interface pages.
|
||||||
None,
|
None,
|
||||||
|
|
||||||
|
/// The Authorization Server should prompt the End-User for
|
||||||
|
/// reauthentication.
|
||||||
Login,
|
Login,
|
||||||
|
|
||||||
|
/// The Authorization Server should prompt the End-User for consent before
|
||||||
|
/// returning information to the Client.
|
||||||
Consent,
|
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,
|
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,
|
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]
|
#[skip_serializing_none]
|
||||||
#[serde_as]
|
#[serde_as]
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct AuthorizationRequest {
|
pub struct AuthorizationRequest {
|
||||||
|
/// OAuth 2.0 Response Type value that determines the authorization
|
||||||
|
/// processing flow to be used.
|
||||||
pub response_type: OAuthAuthorizationEndpointResponseType,
|
pub response_type: OAuthAuthorizationEndpointResponseType,
|
||||||
|
|
||||||
|
/// OAuth 2.0 Client Identifier valid at the Authorization Server.
|
||||||
pub client_id: String,
|
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>,
|
pub redirect_uri: Option<Url>,
|
||||||
|
|
||||||
|
/// The scope of the access request.
|
||||||
|
///
|
||||||
|
/// OpenID Connect requests must contain the `openid` scope value.
|
||||||
pub scope: Scope,
|
pub scope: Scope,
|
||||||
|
|
||||||
|
/// Opaque value used to maintain state between the request and the
|
||||||
|
/// callback.
|
||||||
pub state: Option<String>,
|
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>,
|
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>,
|
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 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(default)]
|
||||||
#[serde_as(as = "Option<DisplayFromStr>")]
|
#[serde_as(as = "Option<DisplayFromStr>")]
|
||||||
pub max_age: Option<NonZeroU32>,
|
pub max_age: Option<NonZeroU32>,
|
||||||
|
|
||||||
|
/// End-User's preferred languages and scripts for the user interface.
|
||||||
#[serde_as(as = "Option<StringWithSeparator::<SpaceSeparator, LanguageTag>>")]
|
#[serde_as(as = "Option<StringWithSeparator::<SpaceSeparator, LanguageTag>>")]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub ui_locales: Option<Vec<LanguageTag>>,
|
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>,
|
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>,
|
pub login_hint: Option<String>,
|
||||||
|
|
||||||
|
/// Requested Authentication Context Class Reference values.
|
||||||
#[serde_as(as = "Option<StringWithSeparator::<SpaceSeparator, String>>")]
|
#[serde_as(as = "Option<StringWithSeparator::<SpaceSeparator, String>>")]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub acr_values: Option<HashSet<String>>,
|
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>,
|
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>,
|
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>,
|
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]
|
#[skip_serializing_none]
|
||||||
#[derive(Serialize, Deserialize, Default, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Default, Debug, Clone)]
|
||||||
pub struct AuthorizationResponse<R> {
|
pub struct AuthorizationResponse<R> {
|
||||||
@ -181,33 +303,58 @@ pub struct AuthorizationResponse<R> {
|
|||||||
pub response: 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]
|
#[skip_serializing_none]
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct AuthorizationCodeGrant {
|
pub struct AuthorizationCodeGrant {
|
||||||
|
/// The authorization code that was returned from the authorization
|
||||||
|
/// endpoint.
|
||||||
pub code: String,
|
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>,
|
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
|
// TODO: move this somehow in the pkce module
|
||||||
#[serde(default)]
|
|
||||||
pub code_verifier: Option<String>,
|
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]
|
#[skip_serializing_none]
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct RefreshTokenGrant {
|
pub struct RefreshTokenGrant {
|
||||||
|
/// The refresh token issued to the client.
|
||||||
pub refresh_token: String,
|
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>,
|
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)]
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct ClientCredentialsGrant {
|
pub struct ClientCredentialsGrant {
|
||||||
#[serde(default)]
|
/// The scope of the access request.
|
||||||
pub scope: Option<Scope>,
|
pub scope: Option<Scope>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// All possible values for the `grant_type` parameter.
|
||||||
#[derive(
|
#[derive(
|
||||||
Debug,
|
Debug,
|
||||||
Hash,
|
Hash,
|
||||||
@ -224,40 +371,62 @@ pub struct ClientCredentialsGrant {
|
|||||||
)]
|
)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum GrantType {
|
pub enum GrantType {
|
||||||
|
/// [`authorization_code`](https://www.rfc-editor.org/rfc/rfc6749#section-4.1)
|
||||||
AuthorizationCode,
|
AuthorizationCode,
|
||||||
|
|
||||||
|
/// [`refresh_token`](https://www.rfc-editor.org/rfc/rfc6749#section-6)
|
||||||
RefreshToken,
|
RefreshToken,
|
||||||
|
|
||||||
|
/// [`implicit`](https://www.rfc-editor.org/rfc/rfc6749#section-4.2)
|
||||||
Implicit,
|
Implicit,
|
||||||
|
|
||||||
|
/// [`client_credentials`](https://www.rfc-editor.org/rfc/rfc6749#section-4.4)
|
||||||
ClientCredentials,
|
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)]
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||||
#[serde(tag = "grant_type", rename_all = "snake_case")]
|
#[serde(tag = "grant_type", rename_all = "snake_case")]
|
||||||
pub enum AccessTokenRequest {
|
pub enum AccessTokenRequest {
|
||||||
AuthorizationCode(AuthorizationCodeGrant),
|
AuthorizationCode(AuthorizationCodeGrant),
|
||||||
RefreshToken(RefreshTokenGrant),
|
RefreshToken(RefreshTokenGrant),
|
||||||
ClientCredentials(ClientCredentialsGrant),
|
ClientCredentials(ClientCredentialsGrant),
|
||||||
#[serde(skip_deserializing, other)]
|
#[serde(skip, other)]
|
||||||
Unsupported,
|
Unsupported,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A successful response from the [Token Endpoint].
|
||||||
|
///
|
||||||
|
/// [Token Endpoint]: https://www.rfc-editor.org/rfc/rfc6749#section-3.2
|
||||||
#[serde_as]
|
#[serde_as]
|
||||||
#[skip_serializing_none]
|
#[skip_serializing_none]
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct AccessTokenResponse {
|
pub struct AccessTokenResponse {
|
||||||
|
/// The access token to access the requested scope.
|
||||||
pub access_token: String,
|
pub access_token: String,
|
||||||
|
|
||||||
|
/// The token to refresh the access token when it expires.
|
||||||
pub refresh_token: Option<String>,
|
pub refresh_token: Option<String>,
|
||||||
|
|
||||||
|
/// ID Token value associated with the authenticated session.
|
||||||
// TODO: this should be somewhere else
|
// TODO: this should be somewhere else
|
||||||
pub id_token: Option<String>,
|
pub id_token: Option<String>,
|
||||||
|
|
||||||
|
/// The type of the access token.
|
||||||
pub token_type: OAuthAccessTokenType,
|
pub token_type: OAuthAccessTokenType,
|
||||||
|
|
||||||
|
/// The duration for which the access token is valid.
|
||||||
#[serde_as(as = "Option<DurationSeconds<i64>>")]
|
#[serde_as(as = "Option<DurationSeconds<i64>>")]
|
||||||
pub expires_in: Option<Duration>,
|
pub expires_in: Option<Duration>,
|
||||||
|
|
||||||
|
/// The scope of the access token.
|
||||||
pub scope: Option<Scope>,
|
pub scope: Option<Scope>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AccessTokenResponse {
|
impl AccessTokenResponse {
|
||||||
|
/// Creates a new `AccessTokenResponse` with the given access token.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(access_token: String) -> AccessTokenResponse {
|
pub fn new(access_token: String) -> AccessTokenResponse {
|
||||||
AccessTokenResponse {
|
AccessTokenResponse {
|
||||||
@ -270,24 +439,28 @@ impl AccessTokenResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds a refresh token to an `AccessTokenResponse`.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn with_refresh_token(mut self, refresh_token: String) -> Self {
|
pub fn with_refresh_token(mut self, refresh_token: String) -> Self {
|
||||||
self.refresh_token = Some(refresh_token);
|
self.refresh_token = Some(refresh_token);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds an ID token to an `AccessTokenResponse`.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn with_id_token(mut self, id_token: String) -> Self {
|
pub fn with_id_token(mut self, id_token: String) -> Self {
|
||||||
self.id_token = Some(id_token);
|
self.id_token = Some(id_token);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds a scope to an `AccessTokenResponse`.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn with_scope(mut self, scope: Scope) -> Self {
|
pub fn with_scope(mut self, scope: Scope) -> Self {
|
||||||
self.scope = Some(scope);
|
self.scope = Some(scope);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds an expiration duration to an `AccessTokenResponse`.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn with_expires_in(mut self, expires_in: Duration) -> Self {
|
pub fn with_expires_in(mut self, expires_in: Duration) -> Self {
|
||||||
self.expires_in = Some(expires_in);
|
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]
|
#[skip_serializing_none]
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct IntrospectionRequest {
|
pub struct IntrospectionRequest {
|
||||||
|
/// The value of the token.
|
||||||
pub token: String,
|
pub token: String,
|
||||||
|
|
||||||
#[serde(default)]
|
/// A hint about the type of the token submitted for introspection.
|
||||||
pub token_type_hint: Option<OAuthTokenTypeHint>,
|
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]
|
#[serde_as]
|
||||||
#[skip_serializing_none]
|
#[skip_serializing_none]
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)]
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)]
|
||||||
pub struct IntrospectionResponse {
|
pub struct IntrospectionResponse {
|
||||||
|
/// Whether or not the presented token is currently active.
|
||||||
pub active: bool,
|
pub active: bool,
|
||||||
|
|
||||||
|
/// The scope associated with the token.
|
||||||
pub scope: Option<Scope>,
|
pub scope: Option<Scope>,
|
||||||
|
|
||||||
|
/// Client identifier for the OAuth 2.0 client that requested this token.
|
||||||
pub client_id: Option<String>,
|
pub client_id: Option<String>,
|
||||||
|
|
||||||
|
/// Human-readable identifier for the resource owner who authorized this
|
||||||
|
/// token.
|
||||||
pub username: Option<String>,
|
pub username: Option<String>,
|
||||||
|
|
||||||
|
/// Type of the token.
|
||||||
pub token_type: Option<OAuthTokenTypeHint>,
|
pub token_type: Option<OAuthTokenTypeHint>,
|
||||||
|
|
||||||
|
/// Timestamp indicating when the token will expire.
|
||||||
#[serde_as(as = "Option<TimestampSeconds>")]
|
#[serde_as(as = "Option<TimestampSeconds>")]
|
||||||
pub exp: Option<DateTime<Utc>>,
|
pub exp: Option<DateTime<Utc>>,
|
||||||
|
|
||||||
|
/// Timestamp indicating when the token was issued.
|
||||||
#[serde_as(as = "Option<TimestampSeconds>")]
|
#[serde_as(as = "Option<TimestampSeconds>")]
|
||||||
pub iat: Option<DateTime<Utc>>,
|
pub iat: Option<DateTime<Utc>>,
|
||||||
|
|
||||||
|
/// Timestamp indicating when the token is not to be used before.
|
||||||
#[serde_as(as = "Option<TimestampSeconds>")]
|
#[serde_as(as = "Option<TimestampSeconds>")]
|
||||||
pub nbf: Option<DateTime<Utc>>,
|
pub nbf: Option<DateTime<Utc>>,
|
||||||
|
|
||||||
|
/// Subject of the token.
|
||||||
pub sub: Option<String>,
|
pub sub: Option<String>,
|
||||||
|
|
||||||
|
/// Intended audience of the token.
|
||||||
pub aud: Option<String>,
|
pub aud: Option<String>,
|
||||||
|
|
||||||
|
/// Issuer of the token.
|
||||||
pub iss: Option<String>,
|
pub iss: Option<String>,
|
||||||
|
|
||||||
|
/// String identifier for the token.
|
||||||
pub jti: Option<String>,
|
pub jti: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user