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

# Authenticate

> Issue a user access token with OAuth 2.0 and PKCE.

## Outcome

The user is logged in and your backend holds a valid `access_token` for subsequent Endaoment API calls.

## When

First step of the [standard journey](./overview). Trigger when the user chooses to connect or sign in to Endaoment from your app.

## Auth

| Phase              | Mechanism                                            |
| ------------------ | ---------------------------------------------------- |
| Authorize redirect | OAuth client ID + PKCE (`code_challenge`, `state`)   |
| Token exchange     | `Authorization: Basic base64(clientId:clientSecret)` |

Store `clientId` and `clientSecret` in server-side environment variables only.

## Endpoints

| Step                     | Method | URL                |
| ------------------------ | ------ | ------------------ |
| Start login              | GET    | `{AUTH_URL}/auth`  |
| Exchange code            | POST   | `{AUTH_URL}/token` |
| Verify caller (optional) | GET    | `/v1/auth/whoami`  |

See also: [Start OAuth authorization](/developers/api/authentication/start-oauth-authorization), [Get access token](/developers/api/authentication/get-access-token), [Revoke access token](/developers/api/authentication/revoke-access-token), [End user session](/developers/api/authentication/end-user-session), and [Get authenticated caller](/developers/api/authentication/get-authenticated-caller) in API reference.

## Required inputs

**Authorize redirect query params:**

| Param                   | Value                                                                                          |
| ----------------------- | ---------------------------------------------------------------------------------------------- |
| `response_type`         | `code`                                                                                         |
| `client_id`             | Your OAuth client ID                                                                           |
| `redirect_uri`          | Registered callback URL                                                                        |
| `scope`                 | `openid accounts transactions profile email address` (add `offline_access` for refresh tokens) |
| `prompt`                | `consent` when requesting `offline_access` (required for refresh tokens)                       |
| `code_challenge`        | PKCE challenge (S256)                                                                          |
| `code_challenge_method` | `S256`                                                                                         |
| `state`                 | Random value you can verify on callback                                                        |

**Token exchange body (`application/x-www-form-urlencoded`):**

| Field           | Value                           |
| --------------- | ------------------------------- |
| `grant_type`    | `authorization_code`            |
| `code`          | Code from callback              |
| `redirect_uri`  | Same URI used in authorize step |
| `code_verifier` | Original PKCE verifier          |

## Example: exchange code for token

```bash theme={null}
curl -X POST "https://auth.dev.endaoment.org/token" \
  -H "Authorization: Basic $(printf '%s:%s' "$CLIENT_ID" "$CLIENT_SECRET" | base64)" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "code=AUTH_CODE_FROM_CALLBACK" \
  -d "redirect_uri=http://localhost:5454/callback" \
  -d "code_verifier=STORED_CODE_VERIFIER"
```

## Response you need

Persist at minimum:

| Field           | Use                                                                                                 |
| --------------- | --------------------------------------------------------------------------------------------------- |
| `access_token`  | Bearer token for API calls                                                                          |
| `expires_in`    | Token lifetime                                                                                      |
| `refresh_token` | Optional long-lived refresh (requires `offline_access` scope **and** `prompt=consent` on authorize) |

## Common mistakes

* Mismatched `redirect_uri` between authorize and token steps
* Losing `code_verifier` between login start and callback
* Requesting `offline_access` without `prompt=consent` (refresh token silently omitted)
* Putting `clientSecret` or access tokens in frontend code

## Full sample

PKCE generation and callback handling: [GitHub quickstart backend](https://github.com/endaoment/endaoment-integration-docs/tree/main/quickstart/backend).

Shared patterns: [Integration Patterns](./integration-patterns).

**Next:** [Open a Fund](./create-daf)
