We use the standard OAuth 2.0 authorization code flow, with 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
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, separated by spaces |
state | Recommended | A random value you check when people come back |
code_challenge | Public apps | Your 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:
https://example.com/callback?code=3kW9...&state=abc123Check that state matches the one you sent. If they said no, or something was wrong with the request, you get an error instead:
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 |
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.
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.
{
"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 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:
- Make a random code verifier: 43 to 128 characters, using
A-Z,a-z,0-9and-._~. - 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:
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(/=+$/, "");
}