# Hosted OAuth - Token exchange

> **POST** `https://api.us.nylas.com/v3/connect/token`

Source: https://developer.nylas.com/docs/reference/api/authentication-apis/exchange_oauth2_token/

The standard OAuth token endpoint for Hosted Authentication. This endpoint doesn't require authentication, as it is part of the auth process.
You can pass one of the following `grant_type` values:
- `authorization_code`: Exchange the `code` Nylas returns from the OAuth 2.0 authorization flow for tokens (`access_token` and `refresh_token`). - `refresh_token`: Use the existing `refresh_token` for an existing grant to issue a new `access_token`. You _must_ pass your API key in the `client_secret` field.
 - `client_credentials`: Issue a new short-lived (1 hour) `access_token` using an existing `grant_id`. You _must_ pass your API key in the `client_secret` field. This is mainly used in Scheduler implementations.

This endpoint accepts both `application/json` and `application/x-www-form-urlencoded` request body types. The body parameters are the same for both, with the same naming conventions.
For more information, see the [Hosted authentication with access token documentation](/docs/v3/auth/hosted-oauth-accesstoken/).
### Failed token exchange requests
Each OAuth `code` is a unique, one-time-use credential. If your token exchange fails, you must restart the OAuth process. If you try to pass the original `code` in another token exchange request, the provider rejects the `code` and Nylas returns an error.

## Request body

Content-Type: application/json

- **Exchange code**
  - `client_id` (string) **(required)** - Your Nylas application's client ID.
  - `client_secret` (string) **(required)** - Your Nylas application's API key.
  - `grant_type` (string) **(required)** - Supports exchanging a `code` for a token, or refreshing an access token using a `refresh_token` and `client_credentials` for issuing short-lived access based on the grant id provided.
  - `code` (string) **(required)** - The `code` from the OAuth 2.0 authorization flow.
  - `redirect_uri` (string) **(required)** - The URL that Nylas uses to redirect the user to your project after they complete
the authorization flow. This should match the `callback_uri` or `redirect_uri` that
you used to get the `code` during your initial
[authorization request](/docs/reference/api/authentication-apis/get_oauth2_flow/).
  - `code_verifier` (string) - The plaintext `code` verifier (`code_challenge`) that you created in your
[authorization request](/docs/reference/api/authentication-apis/get_oauth2_flow/).
- **Refresh access token**
  - `client_id` (string) **(required)** - Your Nylas application's client ID.
  - `client_secret` (string) **(required)** - Your Nylas application's API key.
  - `grant_type` (string) **(required)** - Supports exchanging a `code` for a token, or refreshing an access token using a `refresh_token` and `client_credentials` for issuing short-lived access based on the grant id provided.
  - `refresh_token` (string) **(required)** - Required to refresh or request a short-lived access token.
- **Client credentials**
  - `client_id` (string) **(required)** - Your Nylas application's client ID.
  - `client_secret` (string) **(required)** - Your Nylas application's API key.
  - `grant_type` (string) **(required)** - Supports exchanging a `code` for a token, or refreshing an access token using a `refresh_token` and `client_credentials` for issuing short-lived access based on the grant id provided.
  - `grant_id` (string) **(required)** - Required to request a short-lived access token for a specific grant.

## Responses

### 200 - The token exchange was successful.

- `access_token` (string) - Supports exchanging a `code` for a token, or refreshing an access token using a `refresh_token`.
- `expires_in` (integer) - The remaining lifetime of the access token, in seconds.
- `id_token` (string) - A JSON web token (JWT) that contains identity information about a user. It's digitally
signed by Nylas.
- `email` (string) - The email address associated with the provider token exchange.
- `refresh_token` (string) - Returned only if the `code` was requested using `access_type=offline`.
- `scope` (string) - List of scopes associated with this token.
- `token_type` (string) - Currently always `Bearer`.
- `grant_id` (string) - The ID for the new grant.
- `provider` (string) - The provider name associated with the authorized grant. Only returned during the code exchange process.

### 400 - The token exchange was unsuccessful. Nylas returns a message with a description, and a link to troubleshooting documentation.

- `error` (string) - Error type constant.
- `error_description` (string) - A human-readable error description.
- `error_uri` (string) - A URL to the related documentation and troubleshooting regarding this error.
- `error_code` (string) - Error code used for referencing the documentation, logs, and data stream.

## Code samples

### cURL

```bash
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": "<AUTHORIZATION_CODE>",
    "redirect_uri": "https://example.com/callback-handler",
    "code_verifier": "<CODE_VERIFIER>"
  }'

```

### Node.js SDK

```javascript
import Nylas from "nylas";

const nylas = new Nylas({
  apiKey: "<NYLAS_API_KEY>",
  apiUri: "<NYLAS_API_URI>",
});

// Exchange the authorization code returned by Nylas for an access token and
// grant ID. Call this from your OAuth callback handler with the `code` query
// parameter that Nylas appends to your `redirectUri`.
const code = "<AUTHORIZATION_CODE>";

try {
  const response = await nylas.auth.exchangeCodeForToken({
    clientId: "<NYLAS_CLIENT_ID>",
    redirectUri: "http://localhost:3000/oauth/exchange",
    code,
    // Only set `codeVerifier` if you used PKCE in the initial authorization request.
    // codeVerifier: "<PKCE_CODE_VERIFIER>",
  });

  console.log("Grant ID:", response.grantId);
  console.log("Access token:", response.accessToken);
} catch (error) {
  console.error("Error exchanging code for token:", error);
}

```

### Python SDK

```python
from flask import Flask, request
from nylas import Client

nylas = Client(
    "<NYLAS_API_KEY>",
    "<NYLAS_API_URI>",
)

app = Flask(__name__)
REDIRECT_URI = "http://localhost:9000/oauth/exchange"

@app.route("/oauth/exchange", methods=["GET"])
def exchange_code_for_token():
    code_exchange_response = nylas.auth.exchange_code_for_token(
        request={
            "code": request.args.get("code"),
            "client_id": "<NYLAS_CLIENT_ID>",
            "redirect_uri": REDIRECT_URI,
        }
    )

    return {
        "email_address": code_exchange_response.email,
        "grant_id": code_exchange_response.grant_id,
    }

```

### Ruby SDK

```ruby
# frozen_string_literal: true

require 'nylas'
require 'sinatra'

nylas = Nylas::Client.new(
  api_key: "<NYLAS_API_KEY>"
)

set :show_exceptions, :after_handler

# Receive the authorization code from Nylas and exchange it for a grant.
get '/oauth/exchange' do
  code = params[:code]
  status 404 if code.nil?

  begin
    response = nylas.auth.exchange_code_for_token({
      client_id: "<NYLAS_CLIENT_ID>",
      redirect_uri: 'http://localhost:4567/oauth/exchange',
      code: code
    })
  rescue StandardError
    status 500
  else
    grant_id = response[:grant_id]
    email = response[:email]

    "Grant_Id: #{grant_id} \n Email: #{email}"
  end
end

```

### Java SDK

```java
import com.nylas.NylasClient;
import com.nylas.models.CodeExchangeRequest;
import com.nylas.models.CodeExchangeResponse;

public class ExchangeCodeForToken {
  public static void main(String[] args) {
    NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build();

    // Exchange the authorization code returned by Nylas for an access token and
    // grant ID. Call this from your OAuth callback handler with the `code` query
    // parameter that Nylas appends to your `redirectUri`.
    CodeExchangeRequest codeRequest = new CodeExchangeRequest.Builder(
        "http://localhost:3000/oauth/exchange",
        "<AUTHORIZATION_CODE>",
        "<NYLAS_CLIENT_ID>")
        // Only set codeVerifier if you used PKCE in the initial authorization request.
        // .codeVerifier("<PKCE_CODE_VERIFIER>")
        .build();

    try {
      CodeExchangeResponse codeResponse = nylas.auth().exchangeCodeForToken(codeRequest);

      System.out.println("Grant ID: " + codeResponse.getGrantId());
      System.out.println("Access token: " + codeResponse.getAccessToken());
    } catch (Exception e) {
      System.err.println("Error exchanging code for token: " + e);
    }
  }
}

```

### Kotlin SDK

```kotlin
import com.nylas.NylasClient
import com.nylas.models.CodeExchangeRequest

fun main() {
  val nylas = NylasClient.Builder("<NYLAS_API_KEY>").build()

  // Exchange the authorization code returned by Nylas for an access token and
  // grant ID. Call this from your OAuth callback handler with the `code` query
  // parameter that Nylas appends to your `redirectUri`.
  val codeRequest = CodeExchangeRequest.Builder(
      "http://localhost:3000/oauth/exchange",
      "<AUTHORIZATION_CODE>",
      "<NYLAS_CLIENT_ID>")
      // Only set codeVerifier if you used PKCE in the initial authorization request.
      // .codeVerifier("<PKCE_CODE_VERIFIER>")
      .build()

  try {
    val codeResponse = nylas.auth().exchangeCodeForToken(codeRequest)

    println("Grant ID: ${codeResponse.grantId}")
    println("Access token: ${codeResponse.accessToken}")
  } catch (e: Exception) {
    System.err.println("Error exchanging code for token: $e")
  }
}

```
