actix-jwt-session 1.0.7

Full featured JWT session managment for actix
Documentation
use actix_web::web::{self, Data, ServiceConfig};
use actix_web::HttpResponse;

use crate::*;

pub fn configure<C: Claims>(
    session_info_path: Option<&'static str>,
    refresh_path: &'static str,
    config: &mut ServiceConfig,
) {
    if let Some(session_info) = session_info_path {
        config.service(
            web::resource(session_info)
                .get(|auth: Authenticated<C>| async move { HttpResponse::Ok().json(&*auth) }),
        );
    }
    config.service(web::resource(refresh_path).get(
        |refresh_token: Authenticated<RefreshToken>,
         storage: Data<SessionStorage>,
         extractors: Data<Extractors<_>>| {
            refresh_session::<C>(refresh_token, storage, extractors)
        },
    ));
}

async fn refresh_session<AppClaims: Claims>(
    refresh_token: Authenticated<RefreshToken>,
    storage: Data<SessionStorage>,
    extractors: Data<Extractors<AppClaims>>,
) -> HttpResponse {
    let s = storage.into_inner();
    let pair = match s.refresh::<AppClaims>(refresh_token.access_jti()).await {
        Err(e) => {
            tracing::warn!("Failed to refresh token: {e}");
            return HttpResponse::BadRequest().finish();
        }
        Ok(pair) => pair,
    };

    let encrypted_jwt = match pair.jwt.encode() {
        Ok(text) => text,
        Err(e) => {
            tracing::warn!("Failed to encode claims: {e}");
            return HttpResponse::InternalServerError().finish();
        }
    };
    let encrypted_refresh = match pair.refresh.encode() {
        Err(e) => {
            tracing::warn!("Failed to encode claims: {e}");
            return HttpResponse::InternalServerError().finish();
        }
        Ok(text) => text,
    };

    let mut builder = HttpResponse::Ok();
    let bearer = format!("Bearer {encrypted_jwt}");
    for (_, name) in extractors
        .jwt_extractors
        .iter()
        .filter_map(|e| e.extractor_key())
        .filter(|(kind, _)| *kind == ExtractorKind::Header)
    {
        builder.append_header((name.to_string().as_str(), bearer.as_str()));
    }
    for (_, name) in extractors
        .refresh_extractors
        .iter()
        .filter_map(|e| e.extractor_key())
        .filter(|(kind, _)| *kind == ExtractorKind::Header)
    {
        builder.append_header((name.to_string().as_str(), encrypted_refresh.as_str()));
    }
    builder.append_header((
        "ACX-JWT-TTL",
        (pair.refresh.issues_at + pair.refresh.refresh_ttl.0).to_string(),
    ));
    builder.finish()
}