Skip to main content

Crate limes

Crate limes 

Source
Expand description

License Tests

§Limes

Limes is a multi-tenant capable Authentication middleware for OAuth2.0 and Open ID Connect with optional support for axum. It supports the following Authenticators natively:

  • JWKSWebAuthenticator that fetches JWKs keys from a .well-known/openid-configuration, refreshes keys regularly, and validates tokens locally.
  • KubernetesAuthenticator which validates tokens using Kubernetes TokenReview.
  • AuthenticatorChain holds a collection of Authenticators and authenticates the token with the first suitable Authenticator. This is especially useful for multi-tenant setups where tokens from multiple IdPs should be accepted. Each IdP is assigned a unique idp_id to provide a globally unique Subject that identifies a user.

Custom Authenticators can easily be added by implementing the Authenticator trait.

§Why the Name?

“Limes” is the ancient Roman wall that fortified the ROman Empire. Just like those mighty walls, our Limes library stands guard, protecting your applications from unauthorized access. So, while you won’t find any tangy flavors here, you will find robust authentication to keep your digital empire safe. When life gives you Limes, add auth to your crate! Wait a minute …

§Single-Tenant Example

use axum::{middleware::from_fn_with_state, response::IntoResponse, routing::get, Extension};
use limes::{
    axum::authentication_middleware, format_subject, jwks::JWKSWebAuthenticator, Authentication,
};

// Use none for single tenant setups
const IDP_SEPARATOR: Option<char> = None;

#[tokio::main]
async fn main() {
    let authenticator = JWKSWebAuthenticator::new(
        "https://accounts.google.com", // Must provide ./well-known/openid-configuration
        Some(std::time::Duration::from_secs(10 * 60)), // Refresh JWKS keys every 10 minutes
    )
    .await
    .unwrap()
    .set_accepted_audiences(vec!["my-app".to_string()]); // Acceptable audiences (optional)

    let app = axum::Router::new()
        .route("/whoami", get(whoami))
        .layer(from_fn_with_state(
            authenticator,
            authentication_middleware::<JWKSWebAuthenticator>,
        ));

    let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
        .await
        .unwrap();
    println!("listening on {}", listener.local_addr().unwrap());
    axum::serve(listener, app).await.unwrap();
}

async fn whoami(Extension(auth): Extension<Authentication>) -> impl IntoResponse {
    format!("Hello, {}!", format_subject(auth.subject(), IDP_SEPARATOR))
}

§Multi-Tenant Setup

Limes supports the chained Authenticators. As each Authenticator can point to a different IdP, and subject IDs are not guaranteed to be unique across IdPs, it is important to specify the idp_id for each Authenticator that is used in a AuthenticatorChain.

use axum::{middleware::from_fn_with_state, response::IntoResponse, routing::get, Extension};
use limes::{
    axum::authentication_middleware, format_subject, jwks::JWKSWebAuthenticator,
    kubernetes::KubernetesAuthenticator, Authentication, AuthenticatorChain, AuthenticatorEnum,
};

// We recommend using a character that is never used in subject ids
const IDP_SEPARATOR: Option<char> = Some('~');

#[tokio::main]
async fn main() {
    let oidc_authenticator = JWKSWebAuthenticator::new(
        "https://accounts.google.com", // Must provide ./well-known/openid-configuration
        Some(std::time::Duration::from_secs(10 * 60)), // Refresh JWKS keys every 10 minutes
    )
    .await
    .unwrap()
    .set_idp_id("oidc") // Unique identifier for this IdP. Must never contain the `IDP_SEPARATOR`
    .set_accepted_audiences(vec!["my-app".to_string()]); // Acceptable audiences (optional)

    // Uses the default Kubernetes client. Other constructors are available that accept a custom client.
    let kubernetes_authenticator = KubernetesAuthenticator::try_new_with_default_client(
        Some("kubernetes"), // Unique identifier for this IdP. Must never contain the `IDP_SEPARATOR`
        vec![],             // Don't validate the audience
    )
    .await
    .unwrap();

    // Chain the authenticators together. Order matters.
    // The first authenticator that returns true for `can_handle_token` will be used.
    let chain = AuthenticatorChain::<AuthenticatorEnum>::builder()
        .add_authenticator(oidc_authenticator)
        .add_authenticator(kubernetes_authenticator)
        .build();

    let app = axum::Router::new()
        .route("/whoami", get(whoami))
        .layer(from_fn_with_state(
            chain,
            authentication_middleware::<AuthenticatorChain<AuthenticatorEnum>>,
        ));

    let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
        .await
        .unwrap();
    println!("listening on {}", listener.local_addr().unwrap());
    axum::serve(listener, app).await.unwrap();
}

async fn whoami(Extension(auth): Extension<Authentication>) -> impl IntoResponse {
    format!("Hello, {}!", format_subject(auth.subject(), IDP_SEPARATOR))
    // Would print "oidc~<subject_id>" for google tokens, where oidc is the `idp_id` we set above.
}

§Feature flags

Limes uses a set of feature flags to reduce the amount of compiled code. The following feature flags are available:

  • all: Activate all features
  • default: Includes rustls-tls and jwks.
  • kubernetes: Provides the KubernetesAuthenticator implementation which validates tokens using Kubernetes TokenReview.
  • rustls-tls: Enable rustls for all dependant crates.
  • jwks: Provides the JWKSWebAuthenticator
  • axum: Provides axum middleware that performs the Authentication and provides the tokens Payload as extension.

Modules§

axum
error
introspect
jwks
Validate JWT tokens locally using JWKS keys fetched from a remote server.
kubernetes
Authenticate kubernetes tokens using the Kubernetes TokenReview API.

Structs§

Authentication
Information about a successful authentication. Use Authentication::subject() for a unique identifier of the user.
AuthenticatorChain
Chain multiple authenticators together.
AuthenticatorChainBuilder
Subject
A subject is a unique identifier for a user.

Enums§

AuthenticatorEnum
Enum to hold the different authenticators. This is used for static dispatch in the AuthenticatorChain.
PrincipalType
Type of the principal making the request.

Traits§

Authenticator

Functions§

format_subject
Format a subject as a string. The subject is formatted as <idp_id><separator><sub> if seperator is provided. Otherwise, the subject is formatted as <sub>. Use a separator of None for single tenant setups.
parse_subject
Parse a subject from a string. If separator is provided, the subject is expected to be formatted as <idp_id><separator><sub>. Otherwise, the subject is expected to be formatted as <sub>.