# auth0-integration
Auth0 client library for Rust — handles M2M token retrieval, JWT validation, and user management via the Auth0 Management API.
## Installation
Add the crate to your `Cargo.toml`:
```toml
[dependencies]
auth0-integration = "0.6.1"
tokio = { version = "1", features = ["full"] }
```
## Configuration
The library reads Auth0 credentials from environment variables:
| `AUTH0_DOMAIN` | Auth0 tenant domain (e.g. `your-tenant.us.auth0.com`) |
| `AUTH0_CLIENT_ID` | M2M application client ID |
| `AUTH0_CLIENT_SECRET` | M2M application client secret |
| `AUTH0_AUDIENCE` | API identifier registered in Auth0 |
```rust
use auth0_integration::Auth0Config;
let config = Auth0Config::from_env().expect("Missing Auth0 env vars");
```
## Usage
### Obtaining an M2M access token
Use `Auth0ClientToken` to run the Client Credentials flow.
```rust
use auth0_integration::{Auth0Config, services::Auth0ClientToken};
#[tokio::main]
async fn main() {
let config = Auth0Config::from_env().unwrap();
let client = Auth0ClientToken::new(&config);
let response = client.get_access_token().await.unwrap();
// Print the raw JWT string
println!("{}", response);
// Access the decoded claims
let decoded = response.access_token.decoded().unwrap();
println!("Subject: {}", decoded.sub);
println!("Issuer: {}", decoded.iss);
}
```
### Calling the Auth0 Management API
Pass the raw token string to `Auth0Client` to interact with the Management API.
```rust
use auth0_integration::{Auth0Config, services::{Auth0Client, Auth0ClientToken}};
use auth0_integration::models::UpdateUserRequest;
#[tokio::main]
async fn main() {
let config = Auth0Config::from_env().unwrap();
let response = Auth0ClientToken::new(&config).get_access_token().await.unwrap();
let client = Auth0Client::new(&config, response.access_token.token.clone());
// Look up a user by email
let users = client.get_user_by_email("user@example.com").await.unwrap();
// Create a user with a role (returns error if creation fails)
let role: auth0_integration::Role = "admin".parse().unwrap(); // also: "super_admin", "worker"
let user = client
.create_user("Jane Doe", "jane@example.com", &role)
.await
.unwrap();
// Update a user
let mut req = UpdateUserRequest::new();
req.name = Some("Jane Doe".to_string());
req.blocked = Some(false);
let updated = client.update_user(&user.user_id, req).await.unwrap();
}
```
### Validating a JWT (RS256)
`TokenValidator` verifies the token signature, issuer, and audience against Auth0's JWKS endpoint.
It caches the JWKS keys in memory and refreshes them automatically on a cache miss or validation failure.
Create one instance per application (e.g. wrap in `Arc`) and reuse it across requests.
```rust
use std::sync::Arc;
use auth0_integration::{Auth0Config, TokenValidator};
#[tokio::main]
async fn main() {
let config = Auth0Config::from_env().unwrap();
let validator = Arc::new(TokenValidator::new());
match validator.validate("eyJ...", &config).await {
Ok(data) => println!("Valid! sub = {}", data.claims.sub),
Err(e) => eprintln!("Invalid token: {e}"),
}
}
```
#### Using with Axum state
```rust
use std::sync::Arc;
use axum::{extract::State, http::HeaderMap};
use auth0_integration::{Auth0Config, TokenValidator};
#[derive(Clone)]
struct AppState {
config: Arc<Auth0Config>,
validator: Arc<TokenValidator>,
}
async fn protected(State(state): State<AppState>, headers: HeaderMap) {
let token = headers
.get("Authorization")
.and_then(|v| v.to_str().ok())
.and_then(|v| v.strip_prefix("Bearer "))
.unwrap();
let data = state.validator.validate(token, &state.config).await.unwrap();
println!("sub = {}", data.claims.sub);
}
```
### Checking permissions (scopes)
```rust
use auth0_integration::models::AccessToken;
let token = AccessToken::new("eyJ...".to_string());
// Single permission
let can_read = token.validate_permissions("read:users");
// Multiple — all must be present to return true
let can_manage = token.validate_permissions(["read:users", "update:users"]);
```
### Decoding a token payload (without verification)
```rust
use auth0_integration::models::AccessToken;
let token = AccessToken::new("eyJ...".to_string());
match token.decoded() {
Ok(decoded) => println!("{:?}", decoded),
Err(e) => eprintln!("Invalid token format: {e}"),
}
```
## Key types
| `Auth0Config` | `auth0_integration` | Auth0 credentials loaded from env |
| `AppError` | `auth0_integration` | Unified error type |
| `Auth0ClientToken` | `auth0_integration::services` | Fetches M2M access tokens |
| `Auth0Client` | `auth0_integration::services` | Auth0 Management API client |
| `TokenValidator` | `auth0_integration` | Validates JWT strings against Auth0 JWKS with in-memory key cache |
| `AccessToken` | `auth0_integration::models` | JWT wrapper with lazy decoded payload |
| `AccessTokenResponse` | `auth0_integration::models` | Full token endpoint response |
| `DecodedAccessToken` | `auth0_integration::models` | Typed JWT claims (`sub`, `iss`, `exp`, etc.) |
| `Auth0User` | `auth0_integration::models` | Auth0 user object |
| `Role` | `auth0_integration` | User role enum (`Admin`, `SuperAdmin`, `Worker`); parses from `"admin"` / `"super_admin"` / `"worker"` |
| `UpdateUserRequest` | `auth0_integration::models` | Payload for PATCH `/api/v2/users/{id}` |
| `CreateUserRequest` | `auth0_integration::models` | Payload for POST `/api/v2/users` |
## License
MIT