> **Can't find what you're looking for?** Use `search_docs` on the docs MCP server at `https://docs.ampdb.io/api/mcp` to find what you need.

# Authentication

A [hosted Amp](/get-started/choose-how-to-run-amp#connect-to-a-hosted-amp) checks a token with every request: a JSON
Web Token (JWT), which says who you are and what you may do. An Amp you run yourself doesn't check tokens.

## Prerequisites

* The SDK, [installed](/sdks/typescript#install-the-sdk).
* A token from your Amp's operator, in an environment variable:

  ```bash
  export AMP_AUTH_TOKEN=…
  ```

## Use a token

Pass the token to each service you use:

* For queries, provide `ArrowFlight.layerInterceptorToken` to the transport. It sends the token with every request.
* For the Admin API, set `jwt` in the layer's options.

```ts [amp.ts]
import { ArrowFlight } from "@edgeandnode/amp"
import { layer as layerAdminApi } from "@edgeandnode/amp/admin/service"
import { layerTransportGrpc } from "@edgeandnode/amp/arrow-flight/node"
import { Layer, Redacted } from "effect"
import { FetchHttpClient } from "effect/http"

const token = process.env.AMP_AUTH_TOKEN!

const TransportLayer = layerTransportGrpc({ baseUrl: process.env.AMP_QUERY_URL! }).pipe(
  Layer.provide(ArrowFlight.layerInterceptorToken(Redacted.make(token))),
)
const AdminLayer = layerAdminApi({ url: process.env.AMP_ADMIN_URL!, jwt: token }).pipe(
  Layer.provide(FetchHttpClient.layer),
)
```

[Connecting](/sdks/typescript/connecting#connect-to-a-hosted-amp) shows them in a complete module. Once the token
expires, requests fail until you replace it.

## Sign in

:::note
Signing in isn't available yet. To use a hosted Amp, use a token from its operator.
:::

The `Auth` service signs you in to Edge & Node's hosted Amp, saves your sign-in, and keeps its access token
fresh. It needs the sign-in service for that, and for what depends on a sign-in:

* **Sending your saved sign-in**: provide `ArrowFlight.layerInterceptorBearerAuth` to the transport, and the `Auth`
  service, from [`Auth.layer`](/sdks/typescript/authentication#layer), to `ArrowFlight.layer`. For the Admin API, build `AdminApi` with `layerAuth`
  instead of `layer`. `AdminApi`'s `jwt` option, when set, takes precedence.
* **Signing in from your program**: `createChallenge`, `requestDeviceAuthorization`, and `pollDeviceToken`.
* **Generating a token for an app**: `generateAccessToken`.

## Reference

Import these from `@edgeandnode/amp`'s `Auth` namespace, or from `@edgeandnode/amp/auth/service`.

### `Auth`

```ts
class Auth extends Context.Service<Auth, { … }>
```

The service that signs in and manages tokens. Get it with `yield* Auth.Auth`.

* `createChallenge`: creates a PKCE challenge, a `PKCEChallenge`: `codeVerifier`, a random secret, and
  `codeChallenge`, its SHA-256 hash. An Effect, not a function.
* `requestDeviceAuthorization(codeChallenge)`: starts a device sign-in, and returns a `DeviceAuthorizationResponse`.
  Times out after 30 seconds. Fails with `AuthNetworkError`, `AuthProtocolError`, `AuthRequestError`, or
  `AuthRefreshError`.
* `pollDeviceToken(deviceCode, codeVerifier)`: checks whether the user approved the sign-in, and when they did, saves it
  and returns it, as an `AuthInfo`. Times out after 10 seconds. Fails with `AuthDeviceFlowError` (its `reason` is
  `"pending"` until the user approves, and `"expired"` once the code expired), `AuthCacheError`, `AuthNetworkError`,
  `AuthProtocolError`, or `AuthRequestError`.
* `refreshAccessToken(authInfo)`: gets a new access token with the refresh token, saves it, and returns the new
  `AuthInfo`. Fails with `AuthUserMismatchError` if the new token is for another user, or with `AuthTokenExpiredError`,
  `AuthRateLimitError`, `AuthRefreshError`, `AuthCacheError`, `AuthNetworkError`, `AuthProtocolError`, or
  `AuthRequestError`.
* `generateAccessToken({ authInfo, audience?, duration? })`: generates a token for an app, and returns a
  `GenerateTokenResponse`. `duration` is how long the token lasts, like `"7 days"`, and `audience` the URLs it's valid
  for, which become its `aud` claim. Fails with `AuthTokenExpiredError`, `AuthRateLimitError`, `AuthRefreshError`,
  `AuthNetworkError`, `AuthProtocolError`, or `AuthRequestError`.
* `verifyAccessToken(token, issuer)`: checks `token`'s signature and expiry, and that `issuer` issued it, and returns
  its claims, as a `JWTPayload`. Fails with `AuthVerifyTokenError`.
* `getCachedAuthInfo`: reads the saved sign-in, refreshing it first when it expires within 5 minutes, and returns an
  `Option<AuthInfo>`: `None` when there's none, or the refresh fails. An Effect, not a function. Fails with
  `AuthCacheError`.
* `setCachedAuthInfo(authInfo)`: saves a sign-in. Fails with `AuthCacheError`.
* `clearCachedAuthInfo`: deletes the saved sign-in. An Effect, not a function.

The methods that call the sign-in service, which [isn't available yet](/sdks/typescript/authentication#sign-in), time out after 15 seconds, unless
noted. A timeout fails with an `AuthNetworkError` whose `isTimeout` is `true`.

### `layer`

```ts
const layer: Layer<Auth, never, HttpClient | KeyValueStore>
```

Builds the `Auth` service. Needs an `HttpClient`, like `FetchHttpClient.layer`, and a `KeyValueStore`, where it reads
and saves the sign-in under the key `amp_cli_auth`. `KeyValueStore.layerFileSystem(directory)` stores each key as a
file in `directory`; `KeyValueStore.layerMemory` keeps them in memory, for tests.

### `AUTH_PLATFORM_BASE_URL`

```ts
const AUTH_PLATFORM_BASE_URL: URL
```

The sign-in service's URL, which the `Auth` service calls.

### Types

Each is a schema and a type, of the same name:

| Export                        | What it is                                                                                                                                                    |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `CodeChallenge`               | A PKCE code challenge: a branded non-empty string.                                                                                                            |
| `CodeVerifier`                | A PKCE code verifier: a branded non-empty string.                                                                                                             |
| `PKCEChallenge`               | `{ codeChallenge, codeVerifier }`, what `createChallenge` returns.                                                                                            |
| `DeviceCode`                  | The code that identifies a device sign-in, for `pollDeviceToken`.                                                                                             |
| `UserCode`                    | The code the user enters to approve a device sign-in.                                                                                                         |
| `DeviceAuthorizationResponse` | What `requestDeviceAuthorization` returns: `deviceCode`, `userCode`, `verificationUri`, `expiresIn` (seconds), and `interval` (seconds).                      |
| `DeviceTokenResponse`         | The sign-in service's answer once a sign-in is approved: `accessToken`, `refreshToken`, `userId`, `userAccounts`, and `expiresIn`.                            |
| `DeviceTokenPendingResponse`  | Its answer while the sign-in waits for approval: `{ error: "authorization_pending" }`.                                                                        |
| `DeviceTokenExpiredResponse`  | Its answer once the sign-in's code expired: `{ error: "expired_token" }`.                                                                                     |
| `DeviceTokenPollingResponse`  | Any of the three.                                                                                                                                             |
| `GenerateTokenRequest`        | What `generateAccessToken` sends: `audience` and `duration`.                                                                                                  |
| `GenerateTokenResponse`       | What `generateAccessToken` returns: `token`, `token_type` (`"Bearer"`), `exp`, `sub`, and `iss`.                                                              |
| `RefreshTokenRequest`         | What `refreshAccessToken` sends: `refreshToken` and `userId`.                                                                                                 |
| `RefreshTokenResponse`        | The sign-in service's answer to a refresh: `token`, `refreshToken`, `expiresIn` (1 hour by default), `sessionUpdateAction`, and `user` (`id` and `accounts`). |

`VerifySignedAccessTokenError` is an older error the service no longer uses, kept so code that names it still compiles.

### `AuthErrors`

`@edgeandnode/amp`'s `AuthErrors` namespace, also `@edgeandnode/amp/auth/error`, has the errors, listed in
[Error Codes](/sdks/typescript/error-codes#authentication), and:

| Export                          | What it is                                                                                                               |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| `AuthError`                     | The union of every authentication error.                                                                                 |
| `getUserMessage(error)`         | A sentence describing `error` for a user, without a final period, like `"Your session has expired"`.                     |
| `getUserSuggestion(error)`      | What the user can do about it, like `"Complete the login in your browser"`.                                              |
| `DeviceFlowReason`              | Why a device sign-in failed: `"expired"`, `"pending"`, `"access_denied"`, or `"slow_down"`.                              |
| `CacheOperation`                | What failed on the saved sign-in: `"read"`, `"write"`, or `"clear"`.                                                     |
| `VerifyTokenFailureReason`      | Why a token failed verification: `"expired"`, `"invalid_signature"`, `"invalid_claims"`, `"jwks_error"`, or `"unknown"`. |
| `makeError(code, tag, fields?)` | Creates an error schema with a `_tag`, a `code`, a `message`, and `fields`: how each error here is defined.              |
