# The OAuth flow

How people give your app access, using the OAuth 2.0 authorization code flow.

We use the standard [OAuth 2.0 authorization code flow](https://oauth.net/2/grant-types/authorization-code/), with [PKCE](#pkce) for apps that run in a browser or on a phone. Most OAuth libraries support this out of the box, so you probably won't need to build it yourself.

| Endpoint  | Link                                              |
| --------- | ------------------------------------------------- |
| Authorize | `https://streetartcities.com/api/oauth/authorize` |
| Token     | `https://streetartcities.com/api/oauth/token`     |
| Revoke    | `https://streetartcities.com/api/oauth/revoke`    |

## Overview

```text
 Your app                 Street Art Cities                    Person
    │                             │                               │
    │── 1. send to /authorize ───▶│                               │
    │                             │── 2. log in, allow access? ──▶│
    │                             │◀──────────── yes ─────────────│
    │◀── 3. redirect with code ───│                               │
    │── 4. POST /token ──────────▶│                               │
    │◀── access + refresh token ──│                               │
    │── 5. call the API ─────────▶│                               │
```

## 1. Send people to the authorize page

Send people's browser to the authorize link with these query parameters:

| Parameter               | Required    | Value                                                              |
| ----------------------- | ----------- | ------------------------------------------------------------------ |
| `response_type`         | Yes         | Always `code`                                                      |
| `client_id`             | Yes         | Your app's client ID                                               |
| `redirect_uri`          | Yes         | One of your app's redirect links, exactly as you registered it     |
| `scope`                 | Yes         | One or more [scopes](/authentication/scopes/), separated by spaces |
| `state`                 | Recommended | A random value you check when people come back                     |
| `code_challenge`        | Public apps | Your [PKCE](#pkce) code challenge                                  |
| `code_challenge_method` | Public apps | Always `S256`                                                      |

We show a consent page with your app's name and description, and what it'll be able to do. People who aren't logged in are asked to log in first.

## 2. Handle the redirect

When someone allows access, we send them to your redirect link with a `code` and your `state`:

```text
https://example.com/callback?code=3kW9...&state=abc123
```

Check that `state` matches the one you sent. If they said no, or something was wrong with the request, you get an `error` instead:

```text
https://example.com/callback?error=access_denied&state=abc123
```

| Error                       | Meaning                                                                               |
| --------------------------- | ------------------------------------------------------------------------------------- |
| `access_denied`             | The person didn't allow access                                                        |
| `invalid_scope`             | No scopes, or a scope we don't know                                                   |
| `invalid_request`           | PKCE is missing for an app without a client secret, or the code challenge isn't valid |
| `unsupported_response_type` | `response_type` wasn't `code`                                                         |

<Admonition kind="note">
  If the client ID is unknown or the redirect link isn't registered, we can't
  safely send people back to you. They see an error page on Street Art Cities
  instead.
</Admonition>

## 3. Swap the code for tokens

`POST` to the token link. You can send the body as JSON or as a form (`application/x-www-form-urlencoded`).

| Field           | Value                                     |
| --------------- | ----------------------------------------- |
| `grant_type`    | `authorization_code`                      |
| `code`          | The code from the redirect                |
| `redirect_uri`  | The same redirect link you used in step 1 |
| `code_verifier` | The PKCE code verifier, if you used PKCE  |
| `client_id`     | Your client ID                            |
| `client_secret` | Your client secret, only for server apps  |

Server apps can also send their client ID and secret using HTTP Basic auth instead of in the body.

```json
{
  "access_token": "eyJhbGciOi...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "Yh1c...",
  "scope": "edits:read edits:write"
}
```

Codes work once, and only for 10 minutes. See [tokens](/authentication/tokens/) for what to do when the access token runs out.

## PKCE

Apps that run in a browser, on a phone or on someone's computer can't keep a client secret safe, so they use PKCE instead. It stops someone who intercepts the code from using it. Server apps can use it too, on top of their client secret, but don't have to.

Before step 1:

1. Make a random **code verifier**: 43 to 128 characters, using `A-Z`, `a-z`, `0-9` and `-._~`.
2. Make the **code challenge**: the SHA-256 hash of the verifier, encoded as base64url without padding.

Send the challenge in step 1 and the verifier in step 3. In JavaScript:

```js
const verifier = base64url(crypto.getRandomValues(new Uint8Array(32)));
const challenge = base64url(
  new Uint8Array(
    await crypto.subtle.digest("SHA-256", new TextEncoder().encode(verifier)),
  ),
);

function base64url(bytes) {
  return btoa(String.fromCharCode(...bytes))
    .replace(/\+/g, "-")
    .replace(/\//g, "_")
    .replace(/=+$/, "");
}
```
