> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ooneex.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Auth

> Authenticate requests and manage users with a pluggable, container-managed auth framework.

The `@ooneex/auth` component handles authentication: it verifies bearer tokens, resolves the authenticated user, and enforces role-based route protection. It exposes an `IAuth` interface and a `@decorator.auth()` decorator so you can register any strategy with the container — a local JWT, an OAuth provider, or a third-party identity service.

## Why this component

* **Token verification built in.** Extract a bearer token, verify it, and resolve the current user without wiring the pipeline yourself.
* **Role-aware routing.** Middleware reads each route's `roles` and only enforces authentication on protected routes — guest routes pass through.
* **Pluggable strategies.** Implement `IAuth` to back authentication with any provider while call sites stay unchanged.
* **Container-managed.** Register with a decorator and resolve from the container — no manual wiring.
* **Provider-agnostic call sites.** Controllers read `context.user` and never depend on the underlying auth provider.

## How it works

Authentication runs as middleware in the request pipeline. For each request it:

1. Extracts the token from the `Authorization: Bearer <token>` header (or a `bearerToken` query).
2. Checks the route's `roles` — if the route is guest-only (no roles or `ROLE_GUEST`), it skips verification.
3. Otherwise verifies the token and resolves the user via `getCurrentUser(token)`.
4. Maps the provider's user onto the framework `IUser` and sets it on `context.user`.

```
Request → Bearer token
  → Auth middleware: route requires roles?
      → guest-only  → continue, no token needed
      → protected   → verify token → getCurrentUser(token) → context.user
  → Controller (context.user is available)
```

Downstream controllers read `context.user` — they never import the auth provider directly.

## Decorator and usage

### `@decorator.auth()`

Registers an auth class with the container. It accepts an optional scope (defaults to singleton). A class only needs to implement `getCurrentUser()` to satisfy `IAuth`.

```typescript theme={null}
import { decorator } from "@ooneex/auth";
import type { IAuth } from "@ooneex/auth";

@decorator.auth()
export class JwtAuth implements IAuth {
  public async getCurrentUser(token?: string): Promise<unknown> {
    if (!token) return null;
    // Verify and decode the token, then return the user.
    return verifyAndDecode(token);
  }
}
```

Once registered, the auth middleware uses your strategy to resolve `context.user`. You can also resolve the strategy from the container directly:

```typescript theme={null}
import { container } from "@ooneex/container";

const auth = container.get(JwtAuth);
const user = await auth.getCurrentUser(token);
```

## Protecting routes

Declare the roles a route requires in its `Route` decorator. The middleware enforces authentication only when roles are present; an empty list (or `ROLE_GUEST`) leaves the route open.

```typescript theme={null}
import { Route } from "@ooneex/routing";

@Route.get("/api/profile", {
  name: "profile",
  version: 1,
  description: "Get the current user profile",
  roles: ["ROLE_USER"], // requires a valid token
})
export class ProfileController {
  public async index(context: ContextType<ProfileRouteType>) {
    const { user } = context; // set by the auth middleware
    return context.response.json({
      id: user.id,
      email: user.email,
      roles: user.roles,
    });
  }
}
```

A guest route omits roles, so no token is required:

```typescript theme={null}
@Route.post("/api/login", {
  name: "login",
  version: 1,
  description: "Sign in with email and password",
  roles: [], // guest-only — token not required
})
export class LoginController {
  public async index(context: ContextType<LoginRouteType>) {
    // ...
  }
}
```

## Exceptions

The component throws `AuthException` for authentication failures. It carries a machine-readable `key`, a human-readable `message`, and a `data` object, so callers can branch on the key.

| Key                    | When                                            |
| ---------------------- | ----------------------------------------------- |
| `MISSING_BEARER_TOKEN` | A protected route is requested without a token. |
| `INVALID_TOKEN`        | Token verification fails or resolves no user.   |

```typescript theme={null}
import { AuthException } from "@ooneex/auth";

try {
  const user = await auth.getCurrentUser(token);
  return context.response.json({ user });
} catch (error) {
  if (error instanceof AuthException && error.key === "INVALID_TOKEN") {
    return context.response
      .status(401)
      .json({ error: "Invalid or expired token" });
  }
  throw error;
}
```

## Best practices

* **Drive access from route roles.** Declare `roles` on routes and let the middleware enforce them — don't re-check tokens inside controllers.
* **Read `context.user`, not the provider.** Keep controllers provider-agnostic so the auth strategy can change without touching handlers.
* **Branch on `AuthException.key`.** Return `401` for `MISSING_BEARER_TOKEN` / `INVALID_TOKEN`; keep keys stable and put detail in `data`.
* **Keep verification secrets in the environment.** Load any signing key or provider secret from `.env`; never hard-code it.
* **Fail fast on misconfiguration.** Validate required secrets when the strategy is constructed so problems surface at startup, not at request time.
* **Implement `IAuth` to swap strategies.** Back a custom provider by implementing `getCurrentUser()` and registering it with `@decorator.auth()`.
