Most developers come to Nylas expecting to juggle two OAuth tokens per user: a short-lived access token and a long-lived refresh token they have to store, rotate, and renew on a schedule. With hosted authentication you skip almost all of that. You exchange one code, get a grant_id back, and the API holds and refreshes the provider’s tokens for you.
This recipe explains what each token does, how to get one you can use, and when you’d supply your own refresh tokens instead.
Access tokens vs refresh tokens
Section titled “Access tokens vs refresh tokens”An access token is the short-lived credential that authorizes a single window of API calls; OAuth 2.0 provider access tokens commonly expire after 3,600 seconds (one hour). A refresh token is the long-lived credential that mints a new access token when the old one expires, without sending the user back through consent. It stays valid until it’s revoked.
The split exists so a leaked access token is only useful for an hour, while the refresh token that can renew it stays out of circulation. The table below compares the two.
| Property | Access token | Refresh token |
|---|---|---|
| Purpose | Authorizes API calls for one session | Mints a new access token when one expires |
| Lifetime | Short, about 3,600 seconds (1 hour) | Long, valid until revoked |
| Issued | Every token exchange and refresh | Once, when you request offline access |
| Risk if leaked | Limited to its short window | Higher, can mint fresh access tokens |
With hosted authentication and an API key, you handle neither directly. The provider’s access and refresh tokens stay on the grant, and you act with your grant_id plus your API key.
Exchange the OAuth code for a token
Section titled “Exchange the OAuth code for a token”After a user approves access at their provider, you receive a one-time code at your callback URL. Exchange it with a single POST /v3/connect/token request to finish the flow. The response always includes a grant_id; in access-token mode it also returns a provider access_token valid for about 3,600 seconds and, when you requested offline access, a refresh_token. The code is single-use, so a failed exchange means restarting the flow.
The request below sends the code along with your client ID and API key as client_secret. The hosted OAuth with API key guide walks through the full exchange with runnable SDK examples for every language.
curl --request POST \ --url 'https://api.us.nylas.com/v3/connect/token' \ --header 'Content-Type: application/json' \ --data '{ "client_id": "<NYLAS_CLIENT_ID>", "client_secret": "<NYLAS_API_KEY>", "grant_type": "authorization_code", "code": "<CODE>", "redirect_uri": "<CALLBACK_URI>" }'const response = await nylas.auth.exchangeCodeForToken({ clientId: process.env.NYLAS_CLIENT_ID, redirectUri: "https://myapp.com/callback", code: req.query.code,});
const { grantId } = response;response = nylas.auth.exchange_code_for_token( request={ "client_id": os.environ.get("NYLAS_CLIENT_ID"), "redirect_uri": "https://myapp.com/callback", "code": request.args.get("code"), })
grant_id = response.grant_idIn API-key mode the response carries only the grant_id and email, since you never touch the provider tokens. In access-token mode it returns the access_token for /me/ requests too.
Let Nylas manage token refresh
Section titled “Let Nylas manage token refresh”Token refresh is automatic in API-key mode. The API stores the provider’s access and refresh tokens on the grant and renews the access token before it expires, so a long-lived integration keeps working with zero refresh code in your app. You persist one value, the grant_id, and never the provider’s tokens. A grant stays valid until the user or provider revokes it.
This is the biggest practical difference from rolling your own OAuth. Instead of scheduling refreshes every 3,600 seconds, you make every call with the grant_id and your API key. The connect user accounts with OAuth recipe covers the end-to-end flow, scopes, and the access_type parameter that controls whether a refresh token is issued at all.
Bring your own refresh tokens
Section titled “Bring your own refresh tokens”Bring Your Own Authentication (BYOA) is for teams that already run their own OAuth flow and hold provider refresh tokens. Instead of sending users through hosted auth, you pass 1 existing refresh_token per user to POST /v3/connect/custom to create a grant directly. The response returns a grant_id with grant_status set to valid, which you then use exactly like a hosted-auth grant.
This model fits migrations: you can move thousands of existing users into grants with 1 request per user and no re-consent. One thing to watch, you become responsible for the refresh token you supply, so store it securely. The bring your own authentication guide documents the request body and the custom auth endpoint details every field.
Things to know about tokens
Section titled “Things to know about tokens”A few details decide whether your token handling is secure and resilient. The most important rule: tokens and your API key are server-side credentials only, since one leaked API key exposes every connected mailbox across all 6 providers. The list below covers the cases that bite developers most often, starting with where credentials must never go.
-
Never expose the API key or tokens client-side. Your API key is an application-wide secret, and a single leak grants access to every connected mailbox. Keep it in a secrets manager or environment variable, never in browser or mobile code or a public repository. For client-side flows, use PKCE so the
client_secretfield becomes optional. -
Revoke tokens you no longer need. Send a
POST /v3/connect/revokerequest with the token as a query parameter whenever a user disconnects or re-authenticates. Revoking a Nylas access token also revokes its child tokens. The revoke OAuth token reference lists the response codes, including the 400 returned when a token is already expired. -
Inspect a token before trusting it. Call
GET /v3/connect/tokeninfowith anid_tokenoraccess_tokenquery parameter to read claims like the subject and expiry. This is useful when debugging which grant a token maps to. See the OAuth Token Info reference for the full response. -
Handle the
grant.expiredwebhook. Refresh can still fail when a user changes their password or revokes consent at the provider, which moves the grant to an invalid state. Subscribe to thegrant.expiredwebhook and prompt re-authentication. The handle grant expiry recipe covers detection and recovery without losing sync state. -
Encrypt any token you do store. If you run BYOA and persist provider refresh tokens, encrypt them at rest with a managed key. Follow the security best practices guide for storage requirements.
What’s next
Section titled “What’s next”- Connect user accounts with OAuth for the full hosted flow, scopes, and multi-tenant setup
- Handle grant expiry and re-authentication for the
grant.expiredwebhook and recovery - Authentication overview for the grant model and every auth method
- Bring your own authentication for creating grants from refresh tokens you already hold