openid_client/types/
callback_params.rs

1use std::collections::HashMap;
2
3use josekit::{jwk::Jwk, jwt::JwtPayload};
4use serde::{Deserialize, Serialize};
5use serde_json::Value;
6
7use crate::helpers::get_serde_value_as_string;
8
9/// # CallbackParams
10/// These are the fields that is recieved from the Authorization server to the client.
11/// Which of these fields are present will depend up on the type of authorization request
12#[derive(Default, Serialize, Debug)]
13pub struct CallbackParams {
14    /// Access token obtained
15    pub access_token: Option<String>,
16    /// Authorization code for exchanging at token endpoint
17    pub code: Option<String>,
18    /// Error recieved from the Auth server. [See RFC](https://datatracker.ietf.org/doc/html/rfc6749#appendix-A.7)
19    pub error: Option<String>,
20    /// Error description recieved from the Auth server. [See RFC](https://datatracker.ietf.org/doc/html/rfc6749#appendix-A.7)
21    pub error_description: Option<String>,
22    /// Error uri recieved from the Auth server. [See RFC](https://datatracker.ietf.org/doc/html/rfc6749#appendix-A.7)
23    pub error_uri: Option<String>,
24    /// Token expiry
25    pub expires_in: Option<String>,
26    /// Id token
27    pub id_token: Option<String>,
28    /// State that was recieved from the Auth server
29    pub state: Option<String>,
30    /// Specified the access token type
31    pub token_type: Option<String>,
32    /// Session state
33    pub session_state: Option<String>,
34    /// The JARM response
35    pub response: Option<String>,
36    /// Issuer url
37    pub iss: Option<String>,
38    /// Scopes requested
39    pub scope: Option<String>,
40    /// Other fields received from Auth server
41    #[serde(flatten, skip_serializing_if = "Option::is_none")]
42    pub other: Option<HashMap<String, String>>,
43}
44
45impl CallbackParams {
46    /// Sets the access_token field.
47    pub fn access_token(mut self, access_token: Option<String>) -> Self {
48        self.access_token = access_token;
49        self
50    }
51
52    /// Sets the code field.
53    pub fn code(mut self, code: Option<String>) -> Self {
54        self.code = code;
55        self
56    }
57
58    /// Sets the error field.
59    pub fn error(mut self, error: Option<String>) -> Self {
60        self.error = error;
61        self
62    }
63
64    /// Sets the error_description field.
65    pub fn error_description(mut self, error_description: Option<String>) -> Self {
66        self.error_description = error_description;
67        self
68    }
69
70    /// Sets the error_uri field.
71    pub fn error_uri(mut self, error_uri: Option<String>) -> Self {
72        self.error_uri = error_uri;
73        self
74    }
75
76    /// Sets the expires_in field.
77    pub fn expires_in(mut self, expires_in: Option<String>) -> Self {
78        self.expires_in = expires_in;
79        self
80    }
81
82    /// Sets the id_token field.
83    pub fn id_token(mut self, id_token: Option<String>) -> Self {
84        self.id_token = id_token;
85        self
86    }
87
88    /// Sets the state field.
89    pub fn state(mut self, state: Option<String>) -> Self {
90        self.state = state;
91        self
92    }
93
94    /// Sets the token_type field.
95    pub fn token_type(mut self, token_type: Option<String>) -> Self {
96        self.token_type = token_type;
97        self
98    }
99
100    /// Sets the session_state field.
101    pub fn session_state(mut self, session_state: Option<String>) -> Self {
102        self.session_state = session_state;
103        self
104    }
105
106    /// Sets the response field.
107    pub fn response(mut self, response: Option<String>) -> Self {
108        self.response = response;
109        self
110    }
111
112    /// Sets the iss field.
113    pub fn iss(mut self, iss: Option<String>) -> Self {
114        self.iss = iss;
115        self
116    }
117
118    /// Sets the scope field.
119    pub fn scope(mut self, scope: Option<String>) -> Self {
120        self.scope = scope;
121        self
122    }
123
124    /// Sets the other field.
125    pub fn other(mut self, other: Option<HashMap<String, String>>) -> Self {
126        self.other = other;
127        self
128    }
129}
130
131impl CallbackParams {
132    pub(crate) fn from_jwt_payload(payload: &JwtPayload) -> Self {
133        let mut params = Self {
134            access_token: Self::json_value_to_string_option(payload.claim("access_token")),
135            code: Self::json_value_to_string_option(payload.claim("code")),
136            error: Self::json_value_to_string_option(payload.claim("error")),
137            error_description: Self::json_value_to_string_option(
138                payload.claim("error_description"),
139            ),
140            error_uri: Self::json_value_to_string_option(payload.claim("error_uri")),
141            expires_in: Self::json_value_to_string_option(payload.claim("exp")),
142            id_token: Self::json_value_to_string_option(payload.claim("id_token")),
143            state: Self::json_value_to_string_option(payload.claim("state")),
144            token_type: Self::json_value_to_string_option(payload.claim("token_type")),
145            session_state: Self::json_value_to_string_option(payload.claim("session_state")),
146            response: Self::json_value_to_string_option(payload.claim("response")),
147            iss: Self::json_value_to_string_option(payload.claim("iss")),
148            scope: Self::json_value_to_string_option(payload.claim("scope")),
149            other: None,
150        };
151
152        let mut other = HashMap::<String, String>::new();
153
154        for (k, v) in payload.claims_set().iter() {
155            if let Ok(v_string) = get_serde_value_as_string(v) {
156                other.insert(k.to_string(), v_string);
157            }
158        }
159
160        params.other = Some(other);
161
162        params
163    }
164
165    fn json_value_to_string_option(value: Option<&Value>) -> Option<String> {
166        if let Some(v) = value {
167            return get_serde_value_as_string(v).ok();
168        }
169
170        None
171    }
172}
173
174/// # CallbackExtras
175/// Extra details to be used for the callback
176pub struct CallbackExtras {
177    /// Extra request body properties to be sent to the AS during code exchange.
178    pub exchange_body: Option<HashMap<String, String>>,
179    /// Extra client assertion payload parameters to be sent as part of a client JWT assertion.
180    /// This is only used when the client's token_endpoint_auth_method is either client_secret_jwt or private_key_jwt
181    pub client_assertion_payload: Option<HashMap<String, Value>>,
182    /// When provided the client will send a DPoP Proof JWT.
183    pub dpop: Option<Jwk>,
184}
185
186/// # OAuthCallbackChecks
187/// Checks that needs to be performed against the OAuth [CallbackParams] recieved from the Auth server.
188#[derive(Default, Serialize, Deserialize)]
189pub struct OAuthCallbackChecks<'a> {
190    /// When provided the authorization response will be checked for presence of required parameters for a given response_type. Use of this check is recommended.
191    pub response_type: Option<&'a str>,
192    /// Expected state from the response
193    pub state: Option<&'a str>,
194    /// PKCE code verified to be sent to the token endpoint  
195    pub code_verifier: Option<&'a str>,
196    /// Specifies that the response will be a JARM response
197    pub jarm: Option<bool>,
198}
199
200/// # OpenIDCallbackChecks
201/// Checks that needs to be performed against the Oidc [CallbackParams] recieved from the Auth server.
202#[derive(Default, Serialize, Deserialize)]
203pub struct OpenIDCallbackChecks<'a> {
204    /// When provided the authorization response's ID Token auth_time parameter will be checked to be conform to the max_age value. Use of this check is required if you sent a max_age parameter into an authorization request. Default: uses client's default_max_age.
205    pub max_age: Option<u64>,
206    /// When provided the authorization response's ID Token nonce parameter will be checked to be the this expected one.
207    pub nonce: Option<&'a str>,
208    /// See [OAuthCallbackChecks]
209    pub oauth_checks: Option<OAuthCallbackChecks<'a>>,
210}