arc-auth-jwt 0.8.0

Optional JWT API authentication plugin for Arc
Documentation
use actix_web::{post, web, HttpResponse};
use arc_auth_core::IdentityStore;
use arc_core::session::{SessionRecord, SessionStore};
use arc_web::{ArcAppBuilder, ArcPlugin};
use serde::Deserialize;

pub use arc_web::http::middlewares::jwt_middleware::JwtMiddleware as RequireJwt;

#[derive(Deserialize)]
struct SignIn {
    email: String,
    password: String,
}
#[post("/api/session")]
async fn signin(
    body: web::Json<SignIn>,
    identities: web::Data<dyn IdentityStore>,
    sessions: web::Data<dyn SessionStore>,
) -> HttpResponse {
    let user = match identities.authenticate(&body.email, &body.password).await {
        Ok(user) => user,
        Err(_) => {
            return HttpResponse::Unauthorized()
                .json(serde_json::json!({"error":"invalid credentials"}))
        }
    };
    let (token, jti) = match arc_web::helpers::jwt::create_token(&user.id) {
        Ok(pair) => pair,
        Err(_) => return HttpResponse::InternalServerError().finish(),
    };
    let now = std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH)
        .unwrap_or_default()
        .as_micros() as i64;
    let expires = now + (arc_web::helpers::jwt::get_jwt_expiry() as i64 * 3_600_000_000);
    if sessions
        .record_session(SessionRecord {
            jti,
            actor_id: user.id,
            created_at_us: now,
            expires_at_us: expires,
            revoked_at_us: None,
        })
        .await
        .is_err()
    {
        return HttpResponse::ServiceUnavailable().finish();
    }
    HttpResponse::Ok().json(serde_json::json!({"token":token,"token_type":"Bearer"}))
}
fn routes(cfg: &mut web::ServiceConfig) {
    cfg.service(signin);
}
pub struct JwtAuthPlugin;
#[async_trait::async_trait]
impl ArcPlugin for JwtAuthPlugin {
    fn name(&self) -> &'static str {
        "auth-jwt"
    }
    fn register(&self, builder: ArcAppBuilder) -> ArcAppBuilder {
        builder.register_routes(routes)
    }
}