impl/rust/issue_access_token.rs
3,142 bytes · the Rust implementation · view raw
Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
use super::funejson::Value; ← the fune runtime: the JSON value the test vectors use; fune build keeps it only where a signature takes one
use super::auth_jwt_sign_jwt::sign_jwt;
use super::time_unix_to_iso::unix_to_iso; ← from time.unix-to-iso ^1.0.0 · built alongside by fune
/// A signed access token for a user who has just logged in, with the claims
/// this API relies on: sub, name, email, ver (token version), jti, iat and
/// exp. Everything that varies (the time, the random jti) is passed in.
///
/// # Panics
/// Panics on an empty subject or jti, a negative token version, a ttl below
/// 1, or a secret under 32 bytes.
#[allow(clippy::too_many_arguments)]
pub fn issue_access_token(
subject: &str,
name: &str,
email: &str,
token_version: i64,
jti: &str,
now: i64,
ttl_seconds: i64,
secret: &[i64],
) -> AccessToken {
if subject.is_empty() {
panic!("subject must be a non-empty string");
}
if token_version < 0 {
panic!("tokenVersion must be a whole number, 0 or more");
}
if jti.is_empty() {
panic!("jti must be a non-empty string");
}
if ttl_seconds < 1 {
panic!("ttlSeconds must be a whole number of at least 1");
}
let exp = now + ttl_seconds;
let expires_at = unix_to_iso(exp);
let claims = Value::obj(vec![
("sub", Value::str(subject)),
("name", Value::str(name)),
("email", Value::str(email)),
("ver", Value::Int(token_version)),
("jti", Value::str(jti)),
("iat", Value::Int(now)),
("exp", Value::Int(exp)),
]);
AccessToken {
access_token: sign_jwt(&claims, secret),
token_type: "Bearer".to_string(),
expires_at,
expires_in: ttl_seconds,
}
}
pub fn access_token_to_value(token: &AccessToken) -> Value {
Value::obj(vec![
("accessToken", Value::str(&token.access_token)),
("tokenType", Value::str(&token.token_type)),
("expiresAt", Value::str(&token.expires_at)),
("expiresIn", Value::Int(token.expires_in)),
])
}
pub fn fune_vector(args: &[Value]) -> Value {
let text = |i: usize, message: &str| -> String {
match &args[i] {
Value::Str(s) => s.clone(),
_ => panic!("{}", message),
}
};
let whole = |i: usize, message: &str| -> i64 {
match &args[i] {
Value::Int(n) => *n,
_ => panic!("{}", message),
}
};
let secret: Vec<i64> = match &args[7] {
Value::Arr(items) => items
.iter()
.map(|item| match item {
Value::Int(i) => *i,
_ => panic!("secret must be a list of integers from 0 to 255"),
})
.collect(),
_ => panic!("secret must be a list of integers from 0 to 255"),
};
access_token_to_value(&issue_access_token(
&text(0, "subject must be a non-empty string"),
&text(1, "name must be a string"),
&text(2, "email must be a string"),
whole(3, "tokenVersion must be a whole number, 0 or more"),
&text(4, "jti must be a non-empty string"),
whole(5, "now must be a whole number of Unix seconds"),
whole(6, "ttlSeconds must be a whole number of at least 1"),
&secret,
))
}