Go REST

Bearer-token authentication

How Authorization: Bearer works, where to keep tokens, and why the URL is the wrong place.

Bearer-token authentication is the simplest, most common way modern web APIs identify the caller. The name is exactly what it says: whoever bears (presents) the token is treated as the owner. There is no password to compare, no nonce to verify, no challenge-response. Just send the token, and the server knows who you are.

The header format

The token travels in theAuthorization request header, prefixed withBearer and a single space. The exact wire format is fixed by RFC 6750:

Authorization: Bearer 4f8c9b...e2a1

Two things to remember:

Why not in the URL?

A common shortcut is putting the token in the URL as a query parameter:?api_key=.... This works, but it leaks the token in four places you do not control:

Headers do not appear in any of those places by default. Use theAuthorization header.

Where to keep the token

The "right" place depends on what kind of code is calling the API.

Server-side code (Node, Python, Ruby, Go, etc.)

An environment variable read at boot:process.env.GOREST_TOKEN,os.environ['GOREST_TOKEN'],ENV['GOREST_TOKEN']. Never commit it to the repo. Never log it. In a Twelve-Factor app, it lives in your secrets manager and gets injected at runtime.

Browser apps

This is harder because the browser is hostile territory: anything in the page is reachable by any script that runs in the page (XSS, third-party widgets, browser extensions). The pragmatic options:

Mobile apps

Use the platform's secure storage:Keychain on iOS,EncryptedSharedPreferences on Android. PlainUserDefaults /SharedPreferences is not enough, since those are readable by anyone with file-system access on a rooted device.

What the server actually checks

When a request arrives at Go REST, the API does roughly this:

  1. Pull the code Authorization | header out of the request.
  2. Strip the code Bearer | prefix and look up the remaining string in the code AccessToken | table.
  3. If found, attach the owning user to the request, increment the rate-limit counter for that token, and let the request through.
  4. If not found, return 401 with code= '{ "message": "Invalid token" }' | . If the token has an expiry that has passed, the body is code= '{ "message": "Token expired" }' | instead.

There is no signature, no role, no claims embedded in the token itself; it is an opaque server-side identifier, not a JWT. Tokens optionally carry anexpires field on the server side; if you set one, requests after that timestamp 401 with"Token expired". The advantage of opaque tokens is that revoking is instant: delete the row and the next request 401s. The disadvantage is that the API must hit its database on every request.

Rotation and revocation

Treat tokens as if they will leak some day. The/my-account/access-tokens page lets you generate per-project tokens; doing one token per environment (production, staging, your-laptop) means a leak in one place does not compromise the others. Regenerate any token that has been printed in a screenshot, sent in an email, or pasted into a Slack channel. The regeneration is one click and breaks any old copies.

Common pitfalls

Related guides

Keep going

Back to all guides Try it in the console