jsonoauthsecurityapi

OAuth 2.0 Token Responses: The JSON You Need to Know

·9 min read·Security & Auth

Every OAuth flow ends in JSON

Whatever OAuth 2.0 flow you use — authorization code, client credentials, refresh — it ends the same way: the authorization server returns a JSON token response. Understanding that small object is the key to integrating any "Sign in with…" button or third-party API.

json
{
  "access_token": "eyJhbGciOiJIUzI1NiI...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "def502004f...",
  "scope": "read write"
}

The fields, decoded

FieldMeaning
access_tokenThe credential you send to access protected resources.
token_typeAlmost always Bearer — how to send the token.
expires_inSeconds until the access token expires (e.g. 3600 = 1 hour).
refresh_tokenUsed to get a new access token without re-login.
scopeThe permissions actually granted (may differ from requested).

Using the access token

You send the access token in the Authorization header as a Bearer token:

text
GET /api/me
Authorization: Bearer eyJhbGciOiJIUzI1NiI...

The resource server validates it and returns your data — or 401 if it is missing, expired, or invalid.

Refreshing without re-login

Access tokens are deliberately short-lived. When one expires, exchange the refresh token for a fresh access token:

text
POST /oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token&refresh_token=def502004f...

The response is another token JSON object — often with a new refresh token too (rotation). The pattern: a short-lived access token for requests, a long-lived refresh token kept safe to mint new ones.

access_token vs id_token

OpenID Connect (login) adds an `id_token` to the response. Do not confuse the two:

  • `access_token` — for calling APIs ("what this app can do"). Treat it as opaque; do not parse it for identity.
  • `id_token` — a JWT about the user ("who logged in"). Decode it to get the user's profile claims.

Using an access token where an id token belongs (or vice versa) is a common security mistake.

Handling tokens securely

  • Never log tokens — redact access_token and refresh_token in any JSON you log.
  • Store them securely. On the server, encrypted at rest. In the browser, prefer httpOnly cookies over localStorage, which is exposed to XSS.
  • Honor `expires_in`. Refresh proactively before expiry, not after a failed request.
  • Treat refresh tokens like passwords. They are long-lived; leaking one is a serious breach. Rotate and revoke them.
  • Check `scope`. The server may grant less than you asked for — handle the reduced permission gracefully.

Frequently asked questions

The access token is sent with each API request and is short-lived. The refresh token is long-lived and used only to obtain new access tokens without making the user log in again.

Generally no — for the client it should be treated as opaque. To learn who the user is, decode the OpenID Connect id_token (a JWT) instead.

Prefer secure, httpOnly cookies over localStorage, which is readable by any script and vulnerable to XSS. On the server, store tokens encrypted at rest and never log them.

Try JWT Decoder

Decode the id_token from an OAuth response to inspect claims.