use base64::Engine;
use chrono::{DateTime, Utc};
pub use crate::openhuman::credentials::session_support::get_session_token;
pub use crate::openhuman::credentials::{APP_SESSION_PROVIDER, DEFAULT_AUTH_PROFILE_NAME};
pub fn bearer_authorization_value(token: &str) -> String {
format!("Bearer {}", token.trim())
}
pub fn decode_jwt_payload(token: &str) -> Option<serde_json::Value> {
let payload_b64 = token.trim().split('.').nth(1)?;
let bytes = base64::engine::general_purpose::URL_SAFE_NO_PAD
.decode(payload_b64)
.or_else(|_| base64::engine::general_purpose::URL_SAFE.decode(payload_b64))
.ok()?;
serde_json::from_slice(&bytes).ok()
}
pub fn decode_jwt_exp(token: &str) -> Option<DateTime<Utc>> {
let claims = decode_jwt_payload(token)?;
let exp = claims
.get("exp")
.and_then(|v| v.as_i64().or_else(|| v.as_f64().map(|f| f as i64)))?;
DateTime::<Utc>::from_timestamp(exp, 0)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bearer_authorization_value() {
assert_eq!(bearer_authorization_value("my_token"), "Bearer my_token");
assert_eq!(
bearer_authorization_value(" spaced_token "),
"Bearer spaced_token"
);
assert_eq!(bearer_authorization_value(""), "Bearer ");
assert_eq!(bearer_authorization_value(" "), "Bearer ");
assert_eq!(
bearer_authorization_value("token with spaces"),
"Bearer token with spaces"
);
}
fn jwt_with_payload(payload_json: &str) -> String {
let payload = base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(payload_json);
format!("eyJhbGciOiJIUzI1NiJ9.{payload}.sig")
}
#[test]
fn decode_jwt_exp_reads_integer_exp() {
let token = jwt_with_payload(r#"{"sub":"u1","exp":1700000000}"#);
assert_eq!(
decode_jwt_exp(&token),
DateTime::<Utc>::from_timestamp(1_700_000_000, 0)
);
}
#[test]
fn decode_jwt_exp_reads_float_exp() {
let token = jwt_with_payload(r#"{"exp":1700000000.0}"#);
assert_eq!(
decode_jwt_exp(&token),
DateTime::<Utc>::from_timestamp(1_700_000_000, 0)
);
}
#[test]
fn decode_jwt_exp_none_when_exp_absent() {
let token = jwt_with_payload(r#"{"sub":"u1"}"#);
assert_eq!(decode_jwt_exp(&token), None);
}
#[test]
fn decode_jwt_exp_none_for_non_jwt_or_garbage() {
assert_eq!(decode_jwt_exp("not-a-jwt"), None);
assert_eq!(decode_jwt_exp(""), None);
assert_eq!(decode_jwt_exp("a.b"), None); assert_eq!(decode_jwt_exp("local-session-xyz"), None);
}
}