#actix-web #openid-connect #oidc #middleware #authorization #web-dev

actix_web_openidconnect

Lightweight async OpenID Connect (OIDC) client and middleware for Actix-Web

3 releases

0.1.2 Feb 5, 2024
0.1.1 Feb 5, 2024
0.1.0 Feb 5, 2024

#212 in Authentication

41 downloads per month

MIT/Apache

28KB
410 lines

Actix-Web openid

Lightweight async OpenID Connect (OIDC) client and middleware for Actix-Web.
Support for the Authorization Code Flow
Rely on the excellent openidconnect-rs library for rust

Example

Cargo.toml

[dependencies]
actix-web-openid = "~0.1.2"

main.rs

use actix_web::{App, get, HttpResponse, HttpServer, Responder};
use actix_web::dev::ServiceRequest;
use actix_web_openidconnect::ActixWebOpenId;
use actix_web_openidconnect::openid_middleware::Authenticated;

#[get("/no_auth/hello")]
async fn unauth() -> impl Responder {
    HttpResponse::Ok().body("hello unauth_user")
}

#[get("/is_auth/hello")]
async fn auth(auth_data: Authenticated) -> impl Responder {
    HttpResponse::Ok().body(format!("hello auth_user {:?}. email: {:?}", auth_data.access.preferred_username().unwrap(),
                                    auth_data.access.email()))
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    env_logger::init();
    let should_auth = |req: &ServiceRequest| {
        !req.path().starts_with("/no_auth") && req.method() != actix_web::http::Method::OPTIONS
    };
    let openid = ActixWebOpenId::init("client_id".to_string(),
                                      "client_secret".to_string(),
                                      "http://localhost:8081/auth_callback".to_string(),
                                      "https://my-keycloak.com/realms/myrealm".to_string(),
                                      should_auth,
                                      Some("http://localhost:8081/is_auth/hello".to_string()),
                                      vec!["openid".to_string()]).await;
    HttpServer::new(move || App::new()
        .wrap(openid.get_middleware())
        .configure(openid.configure_open_id())
        .service(unauth)
        .service(auth)
    )
        .bind(("0.0.0.0", 8081))?

        .run()
        .await
}

Parameters

name description Example doc
client_id The client id of the application as defined on your OIDC provider "client_id" keycloak
client_secret The client secret of the application as defined on your OIDC provider "client_secret" keycloak
redirect_url The uri to redirect to after the OIDC provider has authenticated the user. Path need to be /auth_callback. Usually need to be registered in the OIDC Provider "http://localhost:8080/auth_callback" keycloak
issuer_url URL of the OIDC provider "https://my_keycloak.com/realms/my_realm"
should_auth Closure taking an actix_web::service::ServiceRequest in input and returning a boolean. If true the request will need to be authenticate. Allows you to configure which endpoint should be authenticated |req: &ServiceRequest| { !req.path().starts_with("/no_auth") && !req.method() == actix_web::http::Method::OPTIONS };
post_logout_redirect_url Optional url on which the user will be redirected after a logout. Usually need to be registered in the OIDC provider "http://localhost:8080" keycloak
scopes List of scope to be used during the authentication. "openid" scope is required for openid flow [openid, profile, email] keycloak

Features

Authentication middleware

Add a middleware checking user authentication information, and authenticate the user if needed.
Make authentication information available to the endpoint handler

Login

Automatically redirect the user to the OIDC provider when requiring authentication.
Open a callback endpoint (/auth_callback) to redirect the user at the end of the authorization code flow Will store access token, refresh token, id_token and user info in cookies

Logout

Open a logout endpoint (/logout). Calling this endpoint will automatically redirect the user to the openID connect logout

Front end

Make user info contained in the ID token available to the front end through a cookie user_info

Disclaimer

Metadata

This library expect 1 additional metadata to be available on the OIDC provider from what is defined in the OIDC RFC:

Access token

This library is for now agnostic from the Access Token format and use the /userinfo endpoint to get user information and validate this token
This is mainly because the openidconnect-rs library stick to the OIDC RFC which does not define the access token format.
However, as the de-facto standard for access token format is JWT (https://datatracker.ietf.org/doc/html/rfc9068) the library should be updated to support it in the future

TODO

Dependencies

~24–36MB
~671K SLoC