feat(auth): support optional expiry for bot API tokens
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -75,8 +75,16 @@ pub struct AuthResponse {
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct CreateTokenInput {
|
||||
pub name: String,
|
||||
/// Optional lifetime in days. Omit (or `null`) for a non-expiring
|
||||
/// token (the historical behaviour). When set, must be 1..=3650.
|
||||
#[serde(default)]
|
||||
pub expires_in_days: Option<i64>,
|
||||
}
|
||||
|
||||
/// Upper bound on a requested token lifetime (~10 years). A token that needs
|
||||
/// to outlive this should be rotated, not minted once forever.
|
||||
const MAX_TOKEN_EXPIRY_DAYS: i64 = 3650;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct ChangePassword {
|
||||
pub current_password: String,
|
||||
@@ -312,8 +320,22 @@ async fn create_token(
|
||||
details: serde_json::json!({ "name": "max 64 characters" }),
|
||||
});
|
||||
}
|
||||
let expires_at = match input.expires_in_days {
|
||||
None => None,
|
||||
Some(days) if (1..=MAX_TOKEN_EXPIRY_DAYS).contains(&days) => {
|
||||
Some(Utc::now() + Duration::days(days))
|
||||
}
|
||||
Some(_) => {
|
||||
return Err(AppError::ValidationFailed {
|
||||
message: "token expiry out of range".into(),
|
||||
details: serde_json::json!({
|
||||
"expires_in_days": format!("must be between 1 and {MAX_TOKEN_EXPIRY_DAYS}")
|
||||
}),
|
||||
});
|
||||
}
|
||||
};
|
||||
let (raw, hash) = generate_token();
|
||||
let token = repo::api_token::create(&state.db, user.id, name, &hash).await?;
|
||||
let token = repo::api_token::create(&state.db, user.id, name, &hash, expires_at).await?;
|
||||
Ok((
|
||||
StatusCode::CREATED,
|
||||
Json(CreatedTokenResponse { token, bearer: raw }),
|
||||
|
||||
Reference in New Issue
Block a user