this repo has no description
1use super::{Claims, Header, TokenData, UnsafeClaims}; 2use super::token::{TOKEN_TYPE_ACCESS, TOKEN_TYPE_REFRESH, SCOPE_ACCESS, SCOPE_REFRESH, SCOPE_APP_PASS, SCOPE_APP_PASS_PRIVILEGED}; 3use anyhow::{Context, Result, anyhow}; 4use base64::Engine as _; 5use base64::engine::general_purpose::URL_SAFE_NO_PAD; 6use chrono::Utc; 7use k256::ecdsa::{Signature, SigningKey, VerifyingKey, signature::Verifier}; 8 9pub fn get_did_from_token(token: &str) -> Result<String, String> { 10 let parts: Vec<&str> = token.split('.').collect(); 11 if parts.len() != 3 { 12 return Err("Invalid token format".to_string()); 13 } 14 15 let payload_bytes = URL_SAFE_NO_PAD 16 .decode(parts[1]) 17 .map_err(|e| format!("Base64 decode failed: {}", e))?; 18 19 let claims: UnsafeClaims = 20 serde_json::from_slice(&payload_bytes).map_err(|e| format!("JSON decode failed: {}", e))?; 21 22 Ok(claims.sub.unwrap_or(claims.iss)) 23} 24 25pub fn get_jti_from_token(token: &str) -> Result<String, String> { 26 let parts: Vec<&str> = token.split('.').collect(); 27 if parts.len() != 3 { 28 return Err("Invalid token format".to_string()); 29 } 30 31 let payload_bytes = URL_SAFE_NO_PAD 32 .decode(parts[1]) 33 .map_err(|e| format!("Base64 decode failed: {}", e))?; 34 35 let claims: serde_json::Value = 36 serde_json::from_slice(&payload_bytes).map_err(|e| format!("JSON decode failed: {}", e))?; 37 38 claims.get("jti") 39 .and_then(|j| j.as_str()) 40 .map(|s| s.to_string()) 41 .ok_or_else(|| "No jti claim in token".to_string()) 42} 43 44pub fn verify_token(token: &str, key_bytes: &[u8]) -> Result<TokenData<Claims>> { 45 verify_token_internal(token, key_bytes, None, None) 46} 47 48pub fn verify_access_token(token: &str, key_bytes: &[u8]) -> Result<TokenData<Claims>> { 49 verify_token_internal( 50 token, 51 key_bytes, 52 Some(TOKEN_TYPE_ACCESS), 53 Some(&[SCOPE_ACCESS, SCOPE_APP_PASS, SCOPE_APP_PASS_PRIVILEGED]), 54 ) 55} 56 57pub fn verify_refresh_token(token: &str, key_bytes: &[u8]) -> Result<TokenData<Claims>> { 58 verify_token_internal( 59 token, 60 key_bytes, 61 Some(TOKEN_TYPE_REFRESH), 62 Some(&[SCOPE_REFRESH]), 63 ) 64} 65 66fn verify_token_internal( 67 token: &str, 68 key_bytes: &[u8], 69 expected_typ: Option<&str>, 70 allowed_scopes: Option<&[&str]>, 71) -> Result<TokenData<Claims>> { 72 let parts: Vec<&str> = token.split('.').collect(); 73 if parts.len() != 3 { 74 return Err(anyhow!("Invalid token format")); 75 } 76 77 let header_b64 = parts[0]; 78 let claims_b64 = parts[1]; 79 let signature_b64 = parts[2]; 80 81 let header_bytes = URL_SAFE_NO_PAD 82 .decode(header_b64) 83 .context("Base64 decode of header failed")?; 84 let header: Header = 85 serde_json::from_slice(&header_bytes).context("JSON decode of header failed")?; 86 87 if let Some(expected) = expected_typ { 88 if header.typ != expected { 89 return Err(anyhow!("Invalid token type: expected {}, got {}", expected, header.typ)); 90 } 91 } 92 93 let signature_bytes = URL_SAFE_NO_PAD 94 .decode(signature_b64) 95 .context("Base64 decode of signature failed")?; 96 let signature = Signature::from_slice(&signature_bytes) 97 .map_err(|e| anyhow!("Invalid signature format: {}", e))?; 98 99 let signing_key = SigningKey::from_slice(key_bytes)?; 100 let verifying_key = VerifyingKey::from(&signing_key); 101 102 let message = format!("{}.{}", header_b64, claims_b64); 103 verifying_key 104 .verify(message.as_bytes(), &signature) 105 .map_err(|e| anyhow!("Signature verification failed: {}", e))?; 106 107 let claims_bytes = URL_SAFE_NO_PAD 108 .decode(claims_b64) 109 .context("Base64 decode of claims failed")?; 110 let claims: Claims = 111 serde_json::from_slice(&claims_bytes).context("JSON decode of claims failed")?; 112 113 let now = Utc::now().timestamp() as usize; 114 if claims.exp < now { 115 return Err(anyhow!("Token expired")); 116 } 117 118 if let Some(scopes) = allowed_scopes { 119 let token_scope = claims.scope.as_deref().unwrap_or(""); 120 if !scopes.contains(&token_scope) { 121 return Err(anyhow!("Invalid token scope: {}", token_scope)); 122 } 123 } 124 125 Ok(TokenData { claims }) 126}