jacquard_oauth/types/request.rs
1use jacquard_common::IntoStatic;
2use jacquard_common::bos::{BosStr, DefaultStr};
3use serde::{Deserialize, Serialize};
4
5/// The `response_type` parameter for an OAuth 2.0 authorization request.
6///
7/// Determines what the authorization server returns in the redirect response.
8#[derive(Serialize, Deserialize, Debug)]
9#[serde(rename_all = "snake_case")]
10pub enum AuthorizationResponseType {
11 /// Authorization code flow — server returns a short-lived code for token exchange.
12 Code,
13 /// Implicit flow — server returns an access token directly (not recommended for new clients).
14 Token,
15 /// OpenID Connect ID token response (see the
16 /// [multiple response types spec](https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html)).
17 IdToken,
18}
19
20/// The `response_mode` parameter controlling how the authorization response is returned.
21///
22/// Defaults to `query` for `code` response type and `fragment` for `token`.
23#[derive(Serialize, Deserialize, Debug)]
24#[serde(rename_all = "snake_case")]
25pub enum AuthorizationResponseMode {
26 /// Parameters are appended as query string components to the redirect URI.
27 Query,
28 /// Parameters are appended as URI fragment components to the redirect URI.
29 Fragment,
30 /// Parameters are encoded in an HTML form POSTed to the redirect URI.
31 ///
32 /// <https://openid.net/specs/oauth-v2-form-post-response-mode-1_0.html#FormPostResponseMode>
33 FormPost,
34}
35
36/// PKCE code challenge method, as defined in RFC 7636.
37///
38/// `S256` is strongly preferred; `Plain` should only be used when the client
39/// cannot perform SHA-256.
40#[derive(Serialize, Deserialize, Debug)]
41pub enum AuthorizationCodeChallengeMethod {
42 /// SHA-256 hash of the code verifier, base64url-encoded (recommended).
43 S256,
44 /// Raw code verifier used as the challenge (not recommended).
45 #[serde(rename = "plain")]
46 Plain,
47}
48
49/// Parameters for a Pushed Authorization Request (PAR), as defined in RFC 9126.
50///
51/// PAR allows clients to push their authorization parameters directly to the
52/// authorization server before redirecting the user, improving security by keeping
53/// parameters out of the browser URL.
54#[derive(Serialize, Deserialize, Debug)]
55#[serde(bound(deserialize = "S: serde::Deserialize<'de> + BosStr"))]
56pub struct ParParameters<S: BosStr = DefaultStr> {
57 /// The response type to request (e.g. `code`).
58 ///
59 /// <https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.1>
60 pub response_type: AuthorizationResponseType,
61 /// The redirect URI where the authorization response will be sent.
62 pub redirect_uri: S,
63 /// An opaque CSRF state value to be echoed back in the callback.
64 pub state: S,
65 /// Space-separated list of requested scopes.
66 pub scope: Option<S>,
67 /// How the authorization response parameters are delivered to the client.
68 ///
69 /// <https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#ResponseModes>
70 pub response_mode: Option<AuthorizationResponseMode>,
71 /// The PKCE code challenge derived from the code verifier.
72 ///
73 /// <https://datatracker.ietf.org/doc/html/rfc7636#section-4.3>
74 pub code_challenge: S,
75 /// The method used to derive the code challenge.
76 pub code_challenge_method: AuthorizationCodeChallengeMethod,
77 /// Hint to pre-fill the login form with a handle or email.
78 ///
79 /// <https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest>
80 pub login_hint: Option<S>,
81 /// Prompt hint controlling authorization server UI behavior.
82 pub prompt: Option<S>,
83}
84
85/// The `grant_type` parameter for a token endpoint request.
86#[derive(Serialize, Deserialize)]
87#[serde(rename_all = "snake_case")]
88pub enum TokenGrantType {
89 /// Exchange an authorization code for tokens.
90 AuthorizationCode,
91 /// Use a refresh token to obtain a new access token.
92 RefreshToken,
93}
94
95/// Parameters for exchanging an authorization code for tokens (RFC 6749 §4.1.3).
96#[derive(Serialize, Deserialize)]
97#[serde(bound(deserialize = "S: serde::Deserialize<'de> + BosStr"))]
98pub struct TokenRequestParameters<S: BosStr = DefaultStr> {
99 /// Must be `authorization_code` for the authorization code grant.
100 ///
101 /// <https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.3>
102 pub grant_type: TokenGrantType,
103 /// The authorization code received from the authorization server.
104 pub code: S,
105 /// The redirect URI used in the original authorization request.
106 pub redirect_uri: S,
107 /// The PKCE code verifier that was used to generate the code challenge (RFC 7636 §4.5).
108 ///
109 /// <https://datatracker.ietf.org/doc/html/rfc7636#section-4.5>
110 pub code_verifier: S,
111}
112
113/// Parameters for refreshing an access token using a refresh token (RFC 6749 §6).
114#[derive(Serialize, Deserialize)]
115#[serde(bound(deserialize = "S: serde::Deserialize<'de> + BosStr"))]
116pub struct RefreshRequestParameters<S: BosStr = DefaultStr> {
117 /// Must be `refresh_token` for the refresh grant.
118 ///
119 /// <https://datatracker.ietf.org/doc/html/rfc6749#section-6>
120 pub grant_type: TokenGrantType,
121 /// The refresh token previously issued to the client.
122 pub refresh_token: S,
123 /// Optional scope to request; must not exceed the originally granted scope.
124 pub scope: Option<S>,
125}
126
127/// Parameters for a token revocation request (RFC 7009 §2.1).
128///
129/// Sent to the revocation endpoint to invalidate an access or refresh token,
130/// for example on logout.
131///
132/// <https://datatracker.ietf.org/doc/html/rfc7009#section-2.1>
133#[derive(Serialize, Deserialize)]
134#[serde(bound(deserialize = "S: serde::Deserialize<'de> + BosStr"))]
135pub struct RevocationRequestParameters<S: BosStr = DefaultStr> {
136 /// The token to be revoked.
137 pub token: S,
138 // ?
139 // pub token_type_hint: Option<String>,
140}
141
142impl<S: BosStr + IntoStatic> IntoStatic for RevocationRequestParameters<S>
143where
144 S::Output: BosStr,
145{
146 type Output = RevocationRequestParameters<S::Output>;
147
148 fn into_static(self) -> Self::Output {
149 Self::Output {
150 token: self.token.into_static(),
151 }
152 }
153}
154
155impl<S: BosStr + IntoStatic> IntoStatic for TokenRequestParameters<S>
156where
157 S::Output: BosStr,
158{
159 type Output = TokenRequestParameters<S::Output>;
160
161 fn into_static(self) -> Self::Output {
162 Self::Output {
163 grant_type: self.grant_type,
164 code: self.code.into_static(),
165 redirect_uri: self.redirect_uri.into_static(),
166 code_verifier: self.code_verifier.into_static(),
167 }
168 }
169}
170
171impl<S: BosStr + IntoStatic> IntoStatic for RefreshRequestParameters<S>
172where
173 S::Output: BosStr,
174{
175 type Output = RefreshRequestParameters<S::Output>;
176
177 fn into_static(self) -> Self::Output {
178 Self::Output {
179 grant_type: self.grant_type,
180 refresh_token: self.refresh_token.into_static(),
181 scope: self.scope.into_static(),
182 }
183 }
184}
185
186impl<S: BosStr + IntoStatic> IntoStatic for ParParameters<S>
187where
188 S::Output: BosStr,
189{
190 type Output = ParParameters<S::Output>;
191
192 fn into_static(self) -> Self::Output {
193 Self::Output {
194 redirect_uri: self.redirect_uri.into_static(),
195 response_type: self.response_type,
196 scope: self.scope.into_static(),
197 code_challenge: self.code_challenge.into_static(),
198 code_challenge_method: self.code_challenge_method,
199 state: self.state.into_static(),
200 response_mode: self.response_mode,
201 login_hint: self.login_hint.into_static(),
202 prompt: self.prompt.into_static(),
203 }
204 }
205}