Three different token types show up around any real OAuth/OIDC integration, and mixing up their purpose is a common source of bugs.
| Token | Purpose | Typical lifetime | Sent to |
|---|---|---|---|
| Access token | Proves you're allowed to call an API; sent with every API request | Short (minutes to a couple of hours) | The resource server (the API) |
| Refresh token | Used to obtain a new access token without re-authenticating the user | Long (days to months); revocable server-side | Only your own backend's token endpoint — never a resource server |
| ID token (OIDC) | A JWT specifically asserting who the user is — this is the "authentication" half of the picture | Short; typically consumed once at login | Your own application, to establish a local session |
A subtlety worth calling out explicitly: an access token is meant to be opaque to the client — your frontend shouldn't need to (and often structurally can't, if the authorization server issues opaque reference tokens rather than JWTs) parse it to learn anything. An ID token, by contrast, is meant to be read by your application — it's a self-contained, verifiable statement of identity your own backend decodes to learn who just logged in and create a session. Sending an access token to an API that expects an ID token (or vice versa) is a real, recurring integration bug, precisely because both are frequently JWTs and look superficially identical.