tiny_oidc_rp/id_token.rs
1// SPDX-License-Identifier: MIT
2use crate::error::AuthenticationFailedError;
3
4/// OpenID connect ID Token.
5///
6/// More detail, see OpenID Connect Core specification
7///
8/// - [2. ID Token](https://openid.net/specs/openid-connect-core-1_0.html#IDToken) and
9/// - [5.1 Standard Claims](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims)
10///
11/// If you need additionan non-standard claims, make your own struct and specify it to authenticate().
12/// ```ignore
13/// #[derive(serde::Deserialize)]
14/// struct IdTokenExtraClaims {
15/// picture: Option<String>,
16/// }
17/// let id_token_with_picture = oidc_client
18/// .authenticate::<IdTokenExtraClaims>(&state, &code, &session)?;
19/// let picture_url = id_token_with_picture.extra().picture;
20/// ```
21#[derive(serde::Deserialize)]
22pub struct IdToken<T = ()> {
23 pub(crate) iss: String, // Issuer
24 pub(crate) sub: String, // Subject (unique identifier)
25 pub(crate) aud: String, // Audience (must be same as client_id)
26 pub(crate) exp: u64, // Unix time expires at
27 pub(crate) iat: u64, // Unix time issued at
28 pub(crate) nonce: String, // nonce (must be same as nonce of auth request)
29 pub(crate) email: Option<String>,
30 pub(crate) name: Option<String>,
31 /// Extra claims by crate user
32 #[serde(flatten)]
33 pub(crate) extra: T,
34}
35
36impl<T> IdToken<T>
37where
38 T: serde::de::DeserializeOwned,
39{
40 /// Decode IdToken from JWS string
41 /// Warning: This function does not validate JWS signature.
42 /// You can use this function for "code flow" only.
43 pub(crate) fn decode_without_jws_validation(
44 jws: &str,
45 ) -> Result<Self, AuthenticationFailedError> {
46 use base64::{Engine, engine::general_purpose::URL_SAFE_NO_PAD};
47
48 // Decode JWT
49 let mut jws_elm = jws.split('.');
50 let _jws_header = jws_elm.next();
51 let jws_payload = jws_elm.next();
52 let _jws_sign = jws_elm.next();
53
54 if let Some(jws_payload) = jws_payload {
55 let json_str = URL_SAFE_NO_PAD.decode(jws_payload)?;
56 Ok(serde_json::from_slice(&json_str)?)
57 } else {
58 // Invalid JWS structure
59 Err(AuthenticationFailedError::JwsDecodeError)
60 }
61 }
62}
63
64// expose ID Token values
65impl<T> IdToken<T> {
66 /// ID Token issuer
67 pub fn issuer(&self) -> &str {
68 &self.iss
69 }
70
71 /// Subject Identifier.
72 /// A locally unique and never reassigned identifier within the Issuer for the End-User.
73 pub fn subject(&self) -> &str {
74 &self.sub
75 }
76
77 /// End-User's preferred e-mail address.
78 pub fn email(&self) -> Option<&str> {
79 self.email.as_deref()
80 }
81
82 /// End-User's full name in displayable form including all name parts,
83 /// possibly including titles and suffixes,
84 /// ordered according to the End-User's locale and preferences.
85 pub fn name(&self) -> Option<&str> {
86 self.name.as_deref()
87 }
88
89 /// Extra claims
90 pub fn extra(&self) -> &T {
91 &self.extra
92 }
93}