---
title: Authentication
description: Implement bearer token authentication with the AuthVerifier trait and Bearer extractor.
url: https://fast-rs.thally.app/api/authentication
---

# Authentication

Implement bearer token authentication with the AuthVerifier trait and Bearer extractor.

fastrs provides token-based authentication through two pieces: the `AuthVerifier<T>` trait on your application state and the `Bearer<T>` extractor on your handler. Together they read the `Authorization` header, call your verification logic, and either inject the authenticated value into the handler or reject the request with a 401.

## The `AuthVerifier` trait

Implement `AuthVerifier<T>` on your shared state type. The trait has one async method that receives the raw token string and returns either the verified value or an error that converts into `ApiError`.

```rust
#[async_trait]
pub trait AuthVerifier<T>: Send + Sync + 'static {
    type Error: Into<ApiError>;

    async fn verify(&self, token: &str) -> Result<T, Self::Error>;
}
```

`T` is whatever your verification produces: a user ID, a claims struct, a session object. The associated `Error` type must satisfy `Into<ApiError>`, so you can return `ApiError` directly or define a custom error that implements `IntoApiError`.

## The `Bearer` extractor

`Bearer<T>` is a request-parts extractor. When a handler includes `Bearer<T>` in its parameters the extractor:

1. Reads the `Authorization` header. If missing, returns **401**.
2. Strips the `Bearer ` prefix. If the header does not start with `Bearer `, returns **401**.
3. Calls `state.verify(token)`. If verification fails, the error is converted via `Into<ApiError>` and returned as the corresponding HTTP status.
4. On success, injects the verified `T` into the handler.

Because the extractor calls `state.verify()`, the application state type `S` must implement `AuthVerifier<T>`.

## Full example

The example below uses `axum::async_trait`. Add `axum` as a direct dependency in your `Cargo.toml` alongside `fastrs`:

```toml
[dependencies]
fastrs = "0.1"
axum = "0.7"
```

```rust
use axum::async_trait;
use fastrs::{get, App, ApiError, AuthVerifier, Bearer, Json, OpenApi, State};
use serde::Serialize;

// The value produced after successful verification.
#[derive(Clone, Serialize, OpenApi)]
struct UserId(String);

// Application state that knows how to verify tokens.
#[derive(Clone)]
struct AppState {
    secret: String,
}

#[async_trait]
impl AuthVerifier<UserId> for AppState {
    type Error = ApiError;

    async fn verify(&self, token: &str) -> Result<UserId, ApiError> {
        if token == self.secret {
            Ok(UserId("user-42".to_string()))
        } else {
            Err(ApiError::Unauthorized("Invalid token".to_string()))
        }
    }
}

#[get("/me")]
async fn me(Bearer(user): Bearer<UserId>) -> Json<UserId> {
    Json(user)
}

#[tokio::main]
async fn main() {
    let state = AppState {
        secret: "my-secret-token".to_string(),
    };

    App::new()
        .route(me)
        .with_state(state)
        .run("0.0.0.0:3000")
        .await;
}
```

A valid request:

```bash
curl -H "Authorization: Bearer my-secret-token" http://localhost:3000/me
```

A rejected request receives a `401` JSON error:

```json
{"message": "Invalid token"}
```

## Error responses

| Situation | Status | Body |
|-----------|--------|------|
| `Authorization` header missing | **401** | `{"message":"Missing Authorization header"}` |
| Header value is not valid UTF-8 | **400** | `{"message":"Invalid Authorization header encoding"}` |
| Header present but not prefixed with `Bearer ` | **401** | `{"message":"Authorization header must use Bearer token"}` |
| `verify()` returns `Err` | Status determined by the error's `Into<ApiError>` conversion | Error-specific JSON body |

## OpenAPI integration

When a route uses `Bearer<T>`, the generated OpenAPI operation includes a required `Authorization` header parameter with a string schema. The route attribute macros (`#[get]`, `#[post]`, etc.) detect `Bearer<T>` in the handler signature and add an `AuthVerifier` trait bound to the generated route definition automatically.

## Custom header authentication

For schemes that do not use `Authorization: Bearer`, use the `Header<T, V>` extractor with the `HeaderName` trait. See [Extractors](/api/extractors) for details.