1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-07-29 22:01:14 +03:00

Add types for the Device Authorization flow

This commit is contained in:
Kévin Commaille
2022-09-14 19:22:36 +02:00
committed by Quentin Gliech
parent 2e8f233ac5
commit 940ab48819
3 changed files with 122 additions and 0 deletions

View File

@ -225,6 +225,43 @@ pub enum ClientErrorCode {
/// From [RFC7591](https://www.rfc-editor.org/rfc/rfc7591#section-3.2.2). /// From [RFC7591](https://www.rfc-editor.org/rfc/rfc7591#section-3.2.2).
InvalidClientMetadata, InvalidClientMetadata,
/// `authorization_pending`
///
/// The authorization request is still pending as the end user hasn't yet
/// completed the user-interaction steps.
///
/// The client should repeat the access token request to the token endpoint
/// (a process known as polling). Before each new request, the client
/// must wait at least the number of seconds specified by the `interval`
/// parameter of the device authorization response, or 5 seconds if none was
/// provided, and respect any increase in the polling interval required
/// by the [`ClientErrorCode::SlowDown`] error.
///
/// From [RFC8628](https://www.rfc-editor.org/rfc/rfc8628#section-3.5).
AuthorizationPending,
/// `slow_down`
///
/// A variant of [`ClientErrorCode::AuthorizationPending`], the
/// authorization request is still pending and polling should continue,
/// but the interval must be increased by 5 seconds for this and all
/// subsequent requests.
///
/// From [RFC8628](https://www.rfc-editor.org/rfc/rfc8628#section-3.5).
SlowDown,
/// `expired_token`
///
/// The `device_code` has expired, and the device authorization session has
/// concluded.
///
/// The client may commence a new device authorization request but should
/// wait for user interaction before restarting to avoid unnecessary
/// polling.
///
/// From [RFC8628](https://www.rfc-editor.org/rfc/rfc8628#section-3.5).
ExpiredToken,
/// Another error code. /// Another error code.
#[display("{0}")] #[display("{0}")]
Unknown(String), Unknown(String),
@ -304,6 +341,15 @@ impl ClientErrorCode {
ClientErrorCode::InvalidClientMetadata => { ClientErrorCode::InvalidClientMetadata => {
"The value of one of the client metadata fields is invalid" "The value of one of the client metadata fields is invalid"
} }
ClientErrorCode::AuthorizationPending => {
"The authorization request is still pending"
}
ClientErrorCode::SlowDown => {
"The interval must be increased by 5 seconds for this and all subsequent requests"
}
ClientErrorCode::ExpiredToken => {
"The \"device_code\" has expired, and the device authorization session has concluded"
}
ClientErrorCode::Unknown(_) => "", ClientErrorCode::Unknown(_) => "",
} }
} }

View File

@ -357,6 +357,11 @@ pub struct ProviderMetadata {
/// ///
/// [prompt `create`]: https://openid.net/specs/openid-connect-prompt-create-1_0.html /// [prompt `create`]: https://openid.net/specs/openid-connect-prompt-create-1_0.html
pub prompt_values_supported: Option<Vec<Prompt>>, pub prompt_values_supported: Option<Vec<Prompt>>,
/// URL of the authorization server's [device authorization endpoint].
///
/// [device authorization endpoint]: https://www.rfc-editor.org/rfc/rfc8628
pub device_authorization_endpoint: Option<Url>,
} }
impl ProviderMetadata { impl ProviderMetadata {

View File

@ -296,6 +296,65 @@ pub struct AuthorizationResponse<R> {
pub response: R, pub response: R,
} }
/// A request to the [Device Authorization Endpoint].
///
/// [Device Authorization Endpoint]: https://www.rfc-editor.org/rfc/rfc8628
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct DeviceAuthorizationRequest {
/// The scope of the access request.
pub scope: Option<Scope>,
}
pub const DEFAULT_DEVICE_AUTHORIZATION_INTERVAL_SECONDS: i64 = 5;
/// A successful response from the [Device Authorization Endpoint].
///
/// [Device Authorization Endpoint]: https://www.rfc-editor.org/rfc/rfc8628
#[serde_as]
#[skip_serializing_none]
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct DeviceAuthorizationResponse {
/// The device verification code.
device_code: String,
/// The end-user verification code.
user_code: String,
/// The end-user verification URI on the authorization server.
///
/// The URI should be short and easy to remember as end users will be asked
/// to manually type it into their user agent.
verification_uri: Url,
/// A verification URI that includes the `user_code` (or other information
/// with the same function as the `user_code`), which is designed for
/// non-textual transmission.
verification_uri_complete: Option<Url>,
/// The lifetime of the `device_code` and `user_code`.
#[serde_as(as = "DurationSeconds<i64>")]
expires_in: Duration,
/// The minimum amount of time in seconds that the client should wait
/// between polling requests to the token endpoint.
///
/// Defaults to [`DEFAULT_DEVICE_AUTHORIZATION_INTERVAL_SECONDS`].
#[serde_as(as = "Option<DurationSeconds<i64>>")]
interval: Option<Duration>,
}
impl DeviceAuthorizationResponse {
///The minimum amount of time in seconds that the client should wait
/// between polling requests to the token endpoint.
///
/// Defaults to [`DEFAULT_DEVICE_AUTHORIZATION_INTERVAL_SECONDS`].
#[must_use]
pub fn interval(&self) -> Duration {
self.interval
.unwrap_or_else(|| Duration::seconds(DEFAULT_DEVICE_AUTHORIZATION_INTERVAL_SECONDS))
}
}
/// A request to the [Token Endpoint] for the [Authorization Code] grant type. /// A request to the [Token Endpoint] for the [Authorization Code] grant type.
/// ///
/// [Token Endpoint]: https://www.rfc-editor.org/rfc/rfc6749#section-3.2 /// [Token Endpoint]: https://www.rfc-editor.org/rfc/rfc6749#section-3.2
@ -347,6 +406,16 @@ pub struct ClientCredentialsGrant {
pub scope: Option<Scope>, pub scope: Option<Scope>,
} }
/// A request to the [Token Endpoint] for the [Device Authorization] grant type.
///
/// [Token Endpoint]: https://www.rfc-editor.org/rfc/rfc6749#section-3.2
/// [Device Authorization]: https://www.rfc-editor.org/rfc/rfc8628
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct DeviceCodeGrant {
/// The device verification code, from the device authorization response.
pub device_code: Option<Scope>,
}
/// All possible values for the `grant_type` parameter. /// All possible values for the `grant_type` parameter.
#[derive( #[derive(
Debug, Debug,
@ -397,6 +466,8 @@ pub enum AccessTokenRequest {
AuthorizationCode(AuthorizationCodeGrant), AuthorizationCode(AuthorizationCodeGrant),
RefreshToken(RefreshTokenGrant), RefreshToken(RefreshTokenGrant),
ClientCredentials(ClientCredentialsGrant), ClientCredentials(ClientCredentialsGrant),
#[serde(rename = "urn:ietf:params:oauth:grant-type:device_code")]
DeviceCode(DeviceCodeGrant),
#[serde(skip, other)] #[serde(skip, other)]
Unsupported, Unsupported,
} }