# Authentication

Requests to the API carry an OAuth 2.0 access token, or none at all. This guide shows how to get a token, for an application acting on its own and for one acting for a signed-in user.

You don't need a token to read published, public pages: see [Publishing and access](/docs/pages/publishing).
## Register an application

Register each application that calls the API in the console. You get a **client ID**, and a **client secret** if the application can keep one. Choose the type that matches where the application runs:

| Type | Use it for | Signs in | Secret | Refresh tokens |
|---|---|---|---|---|
| Server-side web app | A website with its own server | Users, with the authorization code flow | Yes | Yes |
| Backend service | A job or service with no user, such as a build step | Itself, with client credentials | Yes | No: request a new token |
| Installed app | Anything on a user's own machine: a CLI, a desktop app, a mobile app | Users, with the authorization code flow and PKCE | No | Yes |

Keep the client secret on a server. Anything you ship to a user's machine or browser can be read, which is why an installed app has no secret and must use PKCE instead.
## Endpoints

Sign-in and tokens are handled by an OpenID Connect provider at `https://auth.mountain-labs.io`. Its discovery document lists every endpoint:

```
https://auth.mountain-labs.io/.well-known/openid-configuration
```

Most OAuth and OpenID Connect libraries need only that address, your client ID and, for a server-side application, your client secret. The endpoints you are most likely to need directly:

| Endpoint | Address |
|---|---|
| Authorization | `https://auth.mountain-labs.io/oauth2/authorize` |
| Token | `https://auth.mountain-labs.io/oauth2/token` |
| Signing keys (JWKS) | `https://auth.mountain-labs.io/oauth2/jwks` |
| User info | `https://auth.mountain-labs.io/userinfo` |
| Revocation | `https://auth.mountain-labs.io/oauth2/revoke` |

API requests go to your own endpoint, `https://graph.[username].mountain-labs.io`, with the token in the `Authorization` header:

```
Authorization: Bearer <access_token>
```
## A backend service

A backend service has no user, so it asks for a token for itself with the client credentials grant. Send the client ID and secret with HTTP Basic authentication:

```bash
curl https://auth.mountain-labs.io/oauth2/token \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d grant_type=client_credentials
```

The response carries the token and how many seconds it lasts, for example:

```json
{
  "access_token": "eyJraWQiOi…",
  "token_type": "Bearer",
  "expires_in": 300
}
```

Then call the API with it:

```bash
curl https://graph.[username].mountain-labs.io \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"query": "{ pages(directory: \"/docs\") { edges { node { slug title } } } }"}'
```

There is no refresh token for a backend service. When the token expires, request a new one the same way.

A backend service is treated like an anonymous visitor until you grant it more, so on its own it reads only published, public pages. See [Applications](/docs/pages/publishing#applications).
## Signing users in

A web app or installed app signs users in with the authorization code flow, and then calls the API as that user. To find, edit or remove those users, see [Users](/docs/users/overview) and the [Users API](/docs/api/users/users). Use an OpenID Connect library rather than writing the flow yourself: point it at `https://auth.mountain-labs.io`, and it will find the endpoints from the discovery document.

The flow, in outline:

1. Send the user to the authorization endpoint with your client ID, a `redirect_uri` you registered for the application, `response_type=code`, and, for an installed app, a PKCE `code_challenge`.
2. The user signs in. They come back to your `redirect_uri` with a `code`.
3. Your application exchanges the `code` at the token endpoint for an access token and a refresh token. A server-side web app authenticates with its client secret; an installed app sends its PKCE `code_verifier` instead.
4. Call the API with the access token. When it expires, use the refresh token to get a new one without asking the user to sign in again.

The `redirect_uri` must match one registered for the application exactly, or the sign-in is refused.

A request made with a user's token is judged as that user: it can do whatever your account's `authenticated` permissions allow, drafts included.
---

Previous: [Users overview](/docs/users/overview) · Next: [Hello World](/docs/guides/hello-world)
