use serde::{Deserialize, Serialize};
use serde_aux::prelude::deserialize_bool_from_anything;
use crate::common::{
constants::APPLE_ISSUER,
error::{Error, Result},
jwk::fetch_apple_keys,
};
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct AppleIdentityToken {
pub iss: String,
pub sub: String,
pub aud: String,
pub iat: u64,
pub exp: u64,
pub nonce: Option<String>,
#[serde(
deserialize_with = "deserialize_bool_from_anything",
default
)]
pub nonce_supported: bool,
pub email: Option<String>,
#[serde(
deserialize_with = "deserialize_bool_from_anything",
default = "default_true"
)]
pub email_verified: bool,
#[serde(
deserialize_with = "deserialize_bool_from_anything",
default
)]
pub is_private_email: bool,
pub real_user_status: Option<u8>,
pub transfer_sub: Option<String>,
pub auth_time: u64,
}
fn default_true() -> bool {
true
}
impl AppleIdentityToken {
pub async fn decode(
id_token: &str,
client_id: &str,
validate_exp: bool,
) -> Result<Self> {
let header = Self::decode_header(id_token)?;
let decoding_key =
Self::find_decoding_key(&header.kid.unwrap()).await?;
let mut val = jsonwebtoken::Validation::new(header.alg);
val.validate_exp = validate_exp;
val.set_audience(&[client_id]);
val.set_issuer(&[APPLE_ISSUER]);
let token_data = jsonwebtoken::decode::<AppleIdentityToken>(
id_token,
&decoding_key,
&val,
)?;
Ok(token_data.claims)
}
fn decode_header(token: &str) -> Result<jsonwebtoken::Header> {
let header = jsonwebtoken::decode_header(token)?;
match &header.kid {
Some(_) => Ok(header),
None => Err(Error::KidNotFound),
}
}
async fn find_decoding_key(
kid: &String,
) -> Result<jsonwebtoken::DecodingKey> {
let pubkeys = fetch_apple_keys().await?;
match pubkeys.get(kid) {
Some(key) => {
let decoding_key =
jsonwebtoken::DecodingKey::from_rsa_components(
&key.n, &key.e,
)?;
Ok(decoding_key)
}
None => Err(Error::KeyNotFound),
}
}
}