[−][src]Crate actix_web_middleware_keycloak_auth
actix-web-middleware-keycloak-auth
A middleware for Actix Web that handles authentication with a JWT emitted by Keycloak.
Setup middleware
Setting up the middleware is done in 2 steps:
- creating a
KeycloakAuth
struct with the wanted configuration - passing this struct to an Actix Web service
wrap()
method
use actix_web::{App, web, HttpResponse}; use actix_web_middleware_keycloak_auth::{KeycloakAuth, DecodingKey}; // const KEYCLOAK_PK: &str = "..."; // You should get this from configuration // Initialize middleware configuration let keycloak_auth = KeycloakAuth { detailed_responses: true, keycloak_oid_public_key: DecodingKey::from_rsa_pem(KEYCLOAK_PK.as_bytes()).unwrap(), required_roles: vec![], }; App::new() .service( web::scope("/private") .wrap(keycloak_auth) // Every route in the service will leverage the middleware .route("", web::get().to(|| HttpResponse::Ok().body("Private"))), ) .service(web::resource("/").to(|| HttpResponse::Ok().body("Hello World")));
HTTP requests to GET /private
will need to have a Authorization
header containing Bearer [JWT]
where [JWT]
is a valid JWT that was signed by the private key associated with the public key provided when the middleware was initialized.
Require roles
You can require one or several specific roles to be included in JWT. If they are not provided, the middleware will return a 403 error.
let keycloak_auth = KeycloakAuth { detailed_responses: true, keycloak_oid_public_key: DecodingKey::from_rsa_pem(KEYCLOAK_PK.as_bytes()).unwrap(), required_roles: vec![ Role::Realm { role: "admin".to_owned() }, // The "admin" realm role must be provided in the JWT Role::Client { client: "backoffice".to_owned(), role: "readonly".to_owned() }, // The "readonly" role of the "backoffice" client must be provided in the JWT ], };
Use several authentication profiles
It is possible to setup multiple authentication profiles if, for example, multiple groups of routes require different roles.
use actix_web::{App, web, HttpResponse}; use actix_web_middleware_keycloak_auth::{KeycloakAuth, DecodingKey, Role}; // const KEYCLOAK_PK: &str = "..."; // You should get this from configuration // No role required let keycloak_auth = KeycloakAuth { detailed_responses: true, keycloak_oid_public_key: DecodingKey::from_rsa_pem(KEYCLOAK_PK.as_bytes()).unwrap(), required_roles: vec![], }; // Admin realm role is required let keycloak_auth_admin = KeycloakAuth { detailed_responses: true, keycloak_oid_public_key: DecodingKey::from_rsa_pem(KEYCLOAK_PK.as_bytes()).unwrap(), required_roles: vec![Role::Realm { role: "admin".to_owned() }], }; App::new() .service( web::scope("/private") .wrap(keycloak_auth) // User must be authenticated .route("", web::get().to(|| HttpResponse::Ok().body("Private"))), ) .service( web::scope("/admin") .wrap(keycloak_auth_admin) // User must have the "admin" role .route("", web::get().to(|| HttpResponse::Ok().body("Admin"))), ) .service(web::resource("/").to(|| HttpResponse::Ok().body("Hello World")));
Access claims in handlers
When authentication is successful, the middleware will store the decoded claims so that they can be accessed from handlers.
use actix_web::web::ReqData; use actix_web::{HttpResponse, Responder}; use actix_web_middleware_keycloak_auth::Claims; async fn private(claims: ReqData<Claims>) -> impl Responder { HttpResponse::Ok().body(format!("{:?}", &claims)) }
Structs
Access | Access details |
Claims | Claims that are extracted from JWT and can be accessed in handlers using a |
DecodingKey | (Re-exported from the |
KeycloakAuth | Middleware configuration |
KeycloakAuthMiddleware | Internal middleware configuration |
Enums
Role | A realm or client role |