Closed Sirneij closed 1 year ago
Something in the lines of this should work (note this uses V4), though I haven't compiled it so let me know if it causes any issues you can't correct. If you're bound to using V2 tokens, then claims can be serialized to/from bytes and then be passed directly to encrypt()
as &[u8]
. ClaimsValidationRules
also has validate_claims()
such that you can manually perform the validation.
Perhaps worth to know that you shouldn't use V2 for new systems and prefer V4 instead.
use pasetors::claims::{Claims, ClaimsValidationRules};
use pasetors::keys::{Generate, SymmetricKey};
use pasetors::{local, Local, version4::V4};
use pasetors::token::UntrustedToken;
use core::convert::TryFrom;
pub fn issue_confirmation_token(user_id: uuid::Uuid) -> String {
let settings = crate::settings::get_settings().expect("Cannot load settings.");
let current_date_time = chrono::Utc::now();
let dt = current_date_time + chrono::Duration::minutes(settings.secret.token_expiration);
let mut claims = Claims::new().unwrap();
// Set custom expiration, default is 1 hour
claims.expiration(dt.as_str()).unwrap();
claims.add_additional("user_id", serde_json::json!(user_id)).unwrap();
let sk = SymmetricKey::<V4>::from(settings.secret.secret_key.as_bytes()).unwrap();
let token = local::encrypt(&sk, &claims, None, Some(b"implicit assertion")).unwrap();
return token;
}
pub async fn verify_confirmation_token(token: String) -> Result<crate::types::ConfirmationToken, String> {
let settings = crate::settings::get_settings().expect("Cannot load settings.");
let validation_rules = ClaimsValidationRules::new();
let untrusted_token = UntrustedToken::<Local, V4>::try_from(&token)?;
let trusted_token = local::decrypt(&sk, &untrusted_token, &validation_rules, None, Some(b"implicit assertion"))?;
let claims = trusted_token.payload_claims().unwrap();
let uid = claims.get_claim("user_id")
}
I was able to figure it out using your submission and some modifications. Here it is:
use core::convert::TryFrom;
use pasetors::claims::{Claims, ClaimsValidationRules};
use pasetors::keys::SymmetricKey;
use pasetors::token::UntrustedToken;
use pasetors::{local, version4::V4, Local};
pub fn issue_confirmation_token_pasetors(user_id: uuid::Uuid) -> String {
let settings = crate::settings::get_settings().expect("Cannot load settings.");
let current_date_time = chrono::Utc::now();
let dt = current_date_time + chrono::Duration::minutes(settings.secret.token_expiration);
let mut claims = Claims::new().unwrap();
// Set custom expiration, default is 1 hour
claims.expiration(&dt.to_rfc3339()).unwrap();
claims
.add_additional("user_id", serde_json::json!(user_id))
.unwrap();
let sk = SymmetricKey::<V4>::from(settings.secret.secret_key.as_bytes()).unwrap();
let token = local::encrypt(&sk, &claims, None, Some(b"implicit assertion")).unwrap();
return token;
}
#[tracing::instrument(name = "Verify pasetors token", skip(token))]
pub async fn verify_confirmation_token_pasetor(
token: String,
) -> Result<crate::types::ConfirmationToken, String> {
let settings = crate::settings::get_settings().expect("Cannot load settings.");
let sk = SymmetricKey::<V4>::from(settings.secret.secret_key.as_bytes()).unwrap();
let validation_rules = ClaimsValidationRules::new();
let untrusted_token = UntrustedToken::<Local, V4>::try_from(&token).unwrap();
let trusted_token = local::decrypt(
&sk,
&untrusted_token,
&validation_rules,
None,
Some(b"implicit assertion"),
)
.map_err(|e| format!("Pasetor: {}", e))?;
let claims = trusted_token.payload_claims().unwrap();
let uid = serde_json::to_value(claims.get_claim("user_id").unwrap()).unwrap();
match serde_json::from_value::<String>(uid) {
Ok(uuid_string) => match uuid::Uuid::parse_str(&uuid_string) {
Ok(user_uuid) => Ok(crate::types::ConfirmationToken { user_id: user_uuid }),
Err(e) => Err(format!("{}", e)),
},
Err(e) => Err(format!("{}", e)),
}
}
Kindly check it and suggest any improvement in case there is.
The implicit assertion is not a required argument. Since you don't specify anything specific, you might as well set it None, like the footer.
That's the only thing that sticks out. Of course, the DateTime string (used for expiration) must be valid in terms of ISO 8601 as per the PASETO spec, but I think RFC 3339 is. I'm not certain though.
All right. Thank you.
I am currently using an implementation of
paseto
but it is currently not being maintained again. This crate, implementation, was recommended but I have issues implementing what I want. In the previous crate, I have these two functions:How can I achieve these with this crate. The examples in the docs ain't helping much and I had spent ample time trying to get this to work but all to no avail.