> ## Documentation Index
> Fetch the complete documentation index at: https://docs.smokeball.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Authorization Code Grant

> Use the Authorization Code Grant to authenticate and authorize users

The Authorization Code Grant is a standard OAuth 2.0 flow that enables secure user authentication and authorization. This flow allows applications to obtain an **access\_token** by first receiving an authorization code after the user logs in. The process works as follows:

1. Your application redirects the user to authenticate with their Smokeball credentials
2. Upon successful authentication, Smokeball returns an authorization code to your redirect URI
3. Your application exchanges this code for an **access\_token** that can be used to make authenticated API requests

This is the recommended OAuth 2.0 flow when you need to access the Smokeball API on behalf of a specific user.

## Request User Authorization

Direct the user to `https://auth.smokeball.com/oauth2/authorize` with the following parameters:

Example:

<CodeGroup>
  ```bash curl theme={"dark"}
  curl -X GET 'https://auth.smokeball.com/oauth2/authorize?response_type=code&client_id=xxxxx&redirect_uri=https://xxxxxxxx'
  ```

  ```json http theme={"dark"}
  {
    "method": "GET",
    "url": "https://auth.smokeball.com/oauth2/authorize",
    "query": {
      "response_type": "code",
      "client_id": "xxxxx",
      "redirect_uri": "https://xxxxxxxx"
    }
  }
  ```
</CodeGroup>

<ParamField path="response_type" type="string" required>
  Must be set to "code" for Authorization Code flow.
  Determines the OAuth 2.0 grant type being requested.
</ParamField>

<ParamField path="client_id" type="string" required>
  The client identifier issued during application registration.
  Used to identify the application making the authorization request.
</ParamField>

<ParamField path="redirect_uri" type="string" required>
  The URI where the authorization server will send the authorization code.
  Must match one of the pre-registered redirect URIs.
</ParamField>

<ParamField path="state" type="string">
  An opaque value used to maintain state between request and callback.
  Helps prevent CSRF attacks in the OAuth flow.

  This parameter is optional.
</ParamField>

<ParamField path="scope" type="string">
  The requested scope of access (space-delimited strings).
  Defines the permissions being requested by the application.

  This parameter is optional. Leaving it empty will ensure that all assigned scopes are automatically included in the access token.
</ParamField>

The user will be directed to a login page where they will need to use their Smokeball credentials to login.

If authorized, the user will be redirected to:

```html theme={"dark"}
https://your_redirect_uri?code=xxxxx
```

The response returns a one time use code that is valid for five minutes.

> See [AWS Cognito Authorization Endpoint Documentation](https://docs.aws.amazon.com/cognito/latest/developerguide/authorization-endpoint.html) for more information.

## Request an Access Token

Once you have obtained an authorization code, you can now use it to get an **access\_token** which may be used to make requests to the API.

Make a POST request to `https://auth.smokeball.com/oauth2/token` with the following parameters and headers:

<CodeGroup>
  ```bash curl theme={"dark"}
  curl --request POST \
    --url https://auth.smokeball.com/oauth2/token \
    --header "Authorization: Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=" \
    --header "Content-Type: application/x-www-form-urlencoded" \
    --data-urlencode "grant_type=authorization_code" \
    --data-urlencode "client_id=xxxx" \
    --data-urlencode "redirect_uri=https://xxxxx" \
    --data-urlencode "code=the code acquired from step 1"
  ```

  ```json http theme={"dark"}
  {
    "method": "POST",
    "url": "https://auth.smokeball.com/oauth2/token",
    "headers": {   
      "Authorization": "Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=",
      "Content-Type": "application/x-www-form-urlencoded"
    },
    "body": {
      "grant_type": "authorization_code",
      "client_id": "xxxx",
      "redirect_uri": "https://xxxxx",
      "code": "the code acquired from step 1"
    }
  }
  ```
</CodeGroup>

> The **Authorization** header must be the string "Basic" followed by your client\_id and client\_secret with a colon : in between, Base64 Encoded.
> For example, client\_id:client\_secret is Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=

**Sample Response**

```json theme={"dark"}
HTTP/1.1 200 OK
Content-Type: application/json

{ 
 "refresh_token":"dn43ud8uj32nk2je", 
 "access_token":"dmcxd329ujdmkemkd349r",
 "token_type":"Bearer", 
 "expires_in":3600
}
```

<ResponseField name="refresh_token" type="string">
  A token used to obtain a new access token when the current one expires.

  By default, the returned **refresh\_token** is valid for 30 days. If you require a longer expiration period, please contact us to discuss your specific needs.
</ResponseField>

<ResponseField name="access_token" type="string">
  The access token used to authenticate API requests.

  By default, the returned **access\_token** is valid for 60 minutes.
</ResponseField>

<ResponseField name="token_type" type="string">
  The type of token issued (typically `"Bearer"`).

  Indicates how the token should be presented in API requests.
</ResponseField>

<ResponseField name="expires_in" type="number">
  The lifetime of the access token in **seconds**.

  After expiration, a new token must be obtained.
</ResponseField>

> **Important**: The refresh token expiry is not returned in the above response. Your application is responsible for monitoring the expiration of the refresh token and prompting the user to re-authenticate when it expires. This ensures continuous access to the application without interruptions. See [AWS Cognito Token Endpoint Documentation](https://docs.aws.amazon.com/cognito/latest/developerguide/token-endpoint.html) for more information

<Warning>
  The use of **id\_token** to make API requests has been deprecated. API requests can now also be made using the **access\_token**.

  For further information, see [migration section](#migrating-from-id_token-to-access_token) below for migrating from **id\_token** to **access\_token**.

  Please note that the **id\_token** will continue to work for the time being and **no immediate action is required**.
</Warning>

## PKCE (Proof Key for Code Exchange)

PKCE is an extension of the Authorization Code Grant flow, designed for mobile and single-page applications where storing a client secret securely is difficult. It ensures a more secure flow by requiring a dynamically generated code verifier and code challenge. It is recommended that all authorization code flows are authorized using PKCE and it is *required* for all public api clients, which do not have a client secret.

### Generate a Code Verifier and Code Challenge

To initiate the PKCE flow, you must generate a **code\_verifier**, which is a random string, and a **code\_challenge**, which is derived by hashing the **code\_verifier** using SHA-256 and then Base64-URL encoding it.

<CodeGroup>
  ```csharp c# theme={"dark"}
  using System;
  using System.Security.Cryptography;
  using System.Text;

  class PKCEGenerator
  {
      public static void Main()
      {
          string codeVerifier = GenerateCodeVerifier();
          string codeChallenge = GenerateCodeChallenge(codeVerifier);

          Console.WriteLine("Code Verifier: " + codeVerifier);
          Console.WriteLine("Code Challenge: " + codeChallenge);
      }

      // Generate a random code verifier
      private static string GenerateCodeVerifier()
      {
          var randomBytes = new byte[32]; // 32-byte random string
          using (var rng = RandomNumberGenerator.Create())
          {
              rng.GetBytes(randomBytes);
          }
          return Base64UrlEncode(randomBytes);
      }

      // Create code challenge using SHA256
      private static string GenerateCodeChallenge(string codeVerifier)
      {
          using (var sha256 = SHA256.Create())
          {
              byte[] challengeBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(codeVerifier));
              return Base64UrlEncode(challengeBytes);
          }
      }

      // Base64 URL Encoding (removes padding, uses '-' and '_')
      private static string Base64UrlEncode(byte[] bytes)
      {
          return Convert.ToBase64String(bytes)
              .Replace("+", "-")
              .Replace("/", "_")
              .TrimEnd('=');
      }
  }
  ```

  ```javascript javascript theme={"dark"}
  // Function to generate a random code verifier
  function generateCodeVerifier() {
      const array = new Uint8Array(32); // 32-byte random string
      window.crypto.getRandomValues(array);
      return base64UrlEncode(array);
  }

  // Function to create a code challenge from the code verifier using SHA256
  async function generateCodeChallenge(codeVerifier) {
      const encoder = new TextEncoder();
      const data = encoder.encode(codeVerifier);
      const digest = await crypto.subtle.digest('SHA-256', data);
      return base64UrlEncode(new Uint8Array(digest));
  }

  // Function to Base64 URL encode (removes padding, uses '-' and '_')
  function base64UrlEncode(arrayBuffer) {
      let base64 = btoa(String.fromCharCode.apply(null, arrayBuffer))
          .replace(/\+/g, '-')
          .replace(/\//g, '_')
          .replace(/=+$/, '');
      return base64;
  }

  // Example usage
  (async () => {
      const codeVerifier = generateCodeVerifier();
      const codeChallenge = await generateCodeChallenge(codeVerifier);

      console.log('Code Verifier:', codeVerifier);
      console.log('Code Challenge:', codeChallenge);
  })();
  ```
</CodeGroup>

### Request Authorization Code for Access Token

Direct the user to `https://auth.smokeball.com/oauth2/authorize` with the following parameters:

<CodeGroup>
  ```bash curl theme={"dark"}
  curl --request GET \
    --url "https://auth.smokeball.com/oauth2/authorize?response_type=code&client_id=xxxxx&redirect_uri=https://your_redirect_uri&code_challenge_method=S256&code_challenge=your_code_challenge"
  ```

  ```json http theme={"dark"}
  {
    "method": "GET",
    "url": "https://auth.smokeball.com/oauth2/authorize",
    "query": {
      "response_type": "code",
      "client_id": "xxxxx",
      "redirect_uri": "https://your_redirect_uri",
      "code_challenge_method": "S256",
      "code_challenge": "your_code_challenge"
    }
  }
  ```
</CodeGroup>

<ParamField path="response_type" type="string" required>
  Must be set to "code" for Authorization Code flow.

  Determines the OAuth 2.0 grant type being requested.
</ParamField>

<ParamField path="client_id" type="string" required>
  The client identifier issued during application registration.

  Used to identify the application making the authorization request.
</ParamField>

<ParamField path="redirect_uri" type="string" required>
  The URI where the authorization server will send the authorization code.

  Must match one of the pre-registered redirect URIs.
</ParamField>

<ParamField path="code_challenge" type="string" required>
  The PKCE code challenge derived from the code verifier.

  Generated using the S256 code challenge method.
</ParamField>

<ParamField path="code_challenge_method" type="string" required>
  The hash method used to generate the code challenge (must be "S256").

  Ensures secure PKCE implementation for authorization flow.
</ParamField>

<ParamField path="state" type="string">
  An opaque value used to maintain state between request and callback.

  Helps prevent CSRF attacks in the OAuth flow.

  This parameter is optional.
</ParamField>

<ParamField path="scope" type="string">
  The requested scope of access (space-delimited strings).
  Defines the permissions being requested by the application.

  This parameter is optional. Leaving it empty will ensure that all assigned scopes are automatically included in the access token.
</ParamField>

For Smokeball API, only `S256` method is allowed for `code_challenge_method`

The user will be directed to the login page, and if authorized, redirected back with a code.

### Exchange Authorization Code for Access Token

After receiving the authorization code, use it along with the code\_verifier to request an access token:

<CodeGroup>
  ```bash curl theme={"dark"}
  curl --request POST \
    --url https://auth.smokeball.com/oauth2/token \
    --header "Content-Type: application/x-www-form-urlencoded" \
    --data-urlencode "grant_type=authorization_code" \
    --data-urlencode "client_id=xxxxx" \
    --data-urlencode "code=authorization_code_from_previous_step" \
    --data-urlencode "redirect_uri=https://your_redirect_uri" \
    --data-urlencode "code_verifier=your_code_verifier"
  ```

  ```json http theme={"dark"}
  {
    "method": "POST",
    "url": "https://auth.smokeball.com/oauth2/token",
    "headers": {
      "Content-Type": "application/x-www-form-urlencoded"
    },
    "body": {
      "grant_type": "authorization_code",
      "client_id": "xxxxx",
      "code": "authorization_code_from_previous_step",
      "redirect_uri": "https://your_redirect_uri",
      "code_verifier": "your_code_verifier"
    }
  }
  ```
</CodeGroup>

<ParamField path="grant_type" type="string" required>
  Must be set to "authorization\_code" for this flow.

  Specifies the OAuth 2.0 grant type being used.
</ParamField>

<ParamField path="client_id" type="string" required>
  The client identifier issued during application registration.

  Must match the client\_id used in the authorization request.
</ParamField>

<ParamField path="code" type="string" required>
  The authorization code received from the authorization server.

  This is the code obtained in the previous authorization step.
</ParamField>

<ParamField path="redirect_uri" type="string" required>
  The same redirect URI that was used in the authorization request.

  Must exactly match the previous URI for security validation.
</ParamField>

<ParamField path="code_verifier" type="string" required>
  The original PKCE code verifier that was used to generate the code\_challenge.

  Used to prove possession of the authorization code.
</ParamField>

<ParamField path="client_secret" type="string" required>
  The client secret for confidential clients.

  Required if the client is configured with a secret.
</ParamField>

You will receive an access token that can be used to authenticate API requests.

## Refreshing an Access Token

You can use the **refresh\_token** returned in the previous request to continuously retrieve a valid **access\_token** for use with the API. To exchange a **refresh\_token** for an **access\_token**, make the following request:

<CodeGroup>
  ```bash curl theme={"dark"}
    curl -X POST 'https://auth.smokeball.com/oauth2/token' \
      --header 'Authorization: Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=' \
      --header 'Content-Type: application/x-www-form-urlencoded' \
      --data-urlencode 'grant_type=refresh_token' \
      --data-urlencode 'client_id=xxxxxx' \
      --data-urlencode 'refresh_token=xxxxxx'
  ```

  ```json http theme={"dark"}
  {
    "method": "POST",
    "url": "https://auth.smokeball.com/oauth2/token",
    "headers": {
      "Authorization": "Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=",
      "Content-Type": "application/x-www-form-urlencoded"
    },
    "body": {
      "grant_type": "refresh_token",
      "client_id": "xxxxxx",
      "refresh_token": "xxxxxx"
    }
  }
  ```
</CodeGroup>

<ParamField path="Authorization" type="string" required="true">
  Basic Authentication header containing base64-encoded `client_id:client_secret`.

  Example: `Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=`
</ParamField>

<ParamField path="Content-Type" type="string" required="true">
  Must be `application/x-www-form-urlencoded` for token endpoints.
</ParamField>

<ParamField path="grant_type" type="string" required="true">
  Must be `refresh_token` for this flow.

  Determines the OAuth 2.0 grant type being used.
</ParamField>

<ParamField path="client_id" type="string" required="true">
  The client identifier issued during registration.

  Must match the client ID used in the Basic Auth header.
</ParamField>

<ParamField path="refresh_token" type="string" required="true">
  Previously issued refresh token.

  Used to obtain new access tokens without re-authentication.
</ParamField>

**Sample Response**

```json theme={"dark"}
HTTP/1.1 200 OK
Content-Type: application/json

{
 "access_token":"dmcxd329ujdmkemkd349r",
 "token_type":"Bearer", 
 "expires_in":3600
}
```

<ResponseField name="access_token" type="string" required="true">
  The access token used to authenticate API requests.

  By default, the returned **access\_token** is valid for 60 minutes.
</ResponseField>

<ResponseField name="token_type" type="string" required="true">
  The type of token issued (typically `"Bearer"`).

  Indicates how the token should be presented in API requests.
</ResponseField>

<ResponseField name="expires_in" type="number" required="true">
  The lifetime of the access token in **seconds**.

  After expiration, a new token must be obtained.
</ResponseField>

> See [AWS Cognito User Pool OAuth 2.0 Grants](https://aws.amazon.com/blogs/mobile/understanding-amazon-cognito-user-pool-oauth-2-0-grants/) for more information

## Migrating from Id Token to Access Token

The use of **id\_token** to make API requests has been deprecated.
We will be phasing out issuing an **id\_token** when you request a **token** in the future.

If you have been using an **id\_token** for your API requests, **no immediate action is required**. You will be contacted with instructions for transitioning to the **access\_token**. You can also [contact us via this link](https://marketplace.smokeball.com/application_forms/api-scope-request-form/partner_applications/new) and provide us with a list of endpoints that you need access to so we can verify that your **access\_token** is appropriately configured with the necessary permissions.

> Note: When you transition to **access\_token** you will no longer require to include the `scope` query parameter in your user authorization requests. Please **remember to omit** `scope=openid` from your requests to `https://auth.smokeball.com/oauth2/authorize`, to ensure seamless operation.
