A Rust Actix-web application demonstrating API authorization using AuthAction with JWKS-based JWT validation.
This application shows how to configure and handle authorization using AuthAction's access tokens in an Actix-web API. It validates JSON Web Tokens (JWT) signed with RS256 by fetching public keys dynamically from AuthAction's JWKS endpoint. Public keys are cached in-process using a tokio::sync::RwLock, with automatic single-retry on key rotation.
- Rust 1.75+ (install via rustup)
- AuthAction credentials:
tenantDomainandapiIdentifierfrom your AuthAction account.
-
Clone the repository:
git clone git@github.com:authaction/authaction-rust-actix-example.git cd authaction-rust-actix-example -
Configure your AuthAction credentials:
cp .env.example .env
Edit
.envand replace the placeholders:AUTHACTION_DOMAIN=your-authaction-tenant-domain AUTHACTION_AUDIENCE=your-authaction-api-identifier
-
Start the server:
cargo run
The API will be available at
http://localhost:8080. -
Obtain an access token via client credentials:
curl --request POST \ --url https://your-authaction-tenant-domain/oauth2/m2m/token \ --header 'content-type: application/json' \ --data '{ "client_id": "your-authaction-app-clientid", "client_secret": "your-authaction-app-client-secret", "audience": "your-authaction-api-identifier", "grant_type": "client_credentials" }'
-
Call the public endpoint (no token required):
curl http://localhost:8080/public
{ "message": "This is a public message!" } -
Call the protected endpoint with the access token:
curl --request GET \ --url http://localhost:8080/protected \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'{ "message": "This is a protected message!", "sub": "client-id@clients" }
authaction-rust-actix-example/
├── src/
│ ├── main.rs # Actix-web app setup and route handlers
│ ├── auth.rs # AppState, JWKS cache, JWT validation, AuthenticatedUser extractor
│ └── models.rs # Claims struct
├── Cargo.toml
├── .env.example
└── README.md
Equivalent to JwtStrategy in the NestJS example.
-
AppState— Holds the shareddomain,audience, and atokio::sync::RwLock<Option<Arc<JwkSet>>>JWKS cache. Wrapped inweb::Data<AppState>and shared across all Actix workers. -
get_jwks()— Acquires a read lock and returns the cached key set. On a cache miss, upgrades to a write lock, fetcheshttps://{AUTHACTION_DOMAIN}/.well-known/jwks.jsonviareqwest, and stores anArc<JwkSet>so cloning is O(1). -
verify_token()— Decodes the token header to extractkid, then validates the JWT usingjsonwebtoken::decodewith:- Algorithm:
RS256 - Issuer:
https://{AUTHACTION_DOMAIN}(set_issuer) - Audience:
{AUTHACTION_AUDIENCE}(set_audience)
If the
kidis absent from the cached key set (key rotation), it callsinvalidate_and_refetch()and retries once before returningKeyNotFound. - Algorithm:
-
AuthenticatedUser— An Actix-webFromRequestextractor. Adding it as a handler parameter automatically validates the Bearer token and injects the decodedClaims. Returns HTTP 401 on any validation failure.
GET /public— No extractor, accessible without authentication.GET /protected— Takesuser: AuthenticatedUser; Actix callsFromRequestbefore the handler runs, rejecting invalid/missing tokens.
Invalid token errors — Verify that AUTHACTION_DOMAIN and
AUTHACTION_AUDIENCE match the values in your AuthAction dashboard exactly.
Public key fetching errors — Check that your application can reach
https://{AUTHACTION_DOMAIN}/.well-known/jwks.json.
Unauthorized access — Ensure the Authorization: Bearer <token> header is
present and the token was issued for the correct audience.
Feel free to submit issues or pull requests if you encounter bugs or have suggestions for improvement!