Skip to content
Last updated

To securely access a protected API using OAuth2, follow these steps:

  1. Request a token from the Auth0 token endpoint using your client_id, client_secret, and audience.
  2. Store the token in memory (or cache), along with the expiration time.
  3. Reuse the token for subsequent API requests as long as it's still valid.
  4. Refresh the token by repeating step 1 when it's close to or past expiration.

โš ๏ธ Token Expiration Notice

Tokens obtained via the Client Credentials flow typically expire in 3600 seconds (1 hour). Itโ€™s recommended to subtract a small buffer (e.g., 60 seconds) when checking for expiration to avoid race conditions.

๐Ÿงพ Token Endpoint Specification

POST https://bookabletech.uk.auth0.com/oauth/token
Content-Type: application/json

{
  "grant_type": "client_credentials",
  "client_id": "YOUR_CLIENT_ID",
  "client_secret": "YOUR_CLIENT_SECRET",
  "audience": "api.bookabletech.com"
}

Expected response:

{
    "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtMUDc4SkVmTWdERi1wdXEyckduZyJ9.eyJodHRwczovL2FwaS5ib29rYWJsZXRlY2guY29tL2FwcF9tZXRhZGF0YSI6eyJzbHVnIjoiYm90dG9tbGVzc2JydW5jaCJ9LCJpc3MiOiJodHRwczovL2Jvb2thYmxldGVjaC51ay5hdXRoMC5jb20vIiwic3ViIjoiVWVjYnVoQ3Z5TnA1Vk5uNWNkajJodVhiSUJ2Z0RMNlpAY2xpZW50cyIsImF1ZCI6ImFwaS5ib29rYWJsZXRlY2guY29tIiwiaWF0IjoxNzQ3NjQ5NjE2LCJleHAiOjE3NTAyNDE2MTYsInNjb3BlIjoidmVudWU6cmVhZCB2ZW51ZS1ib29raW5nOmNyZWF0ZSIsImd0eSI6ImNsaWVudC1jcmVkZW50aWFscyIsImF6cCI6IlVlY2J1aEN2eU5wNVZObjVjZGoyaHVYYklCdmdETDZaIiwicGVybWlzc2lvbnMiOlsidmVudWU6cmVhZCIsInZlbnVlLWJvb2tpbmc6Y3JlYXRlIl19.PFcKgigRn5TVcUIxxgnNE9pcjQ9gZ2wb3MplGaMkOX_zSvawKXY189F8FPS58HsDn3IXJqzJVHXRIJuaNJJYY96tqYtMD0xou6zyYhLMctdHpMBfnmBVyH7WnMcdN_chaZ83IVn1yFwtyPyAMvgkwaprs16I6ib3ejhhn0sB4NgXIo7I8Pacl2-9amLVsv1mjs66n2DX0_jY29pBCM0hvcBvK-XB37kXHEFkUb5mJizZBW2Q_tk0Uh48JitIg-RIeZVTKkGCYgXYuaEwrDL62oLa2eig_N6CTveJm3qgpqquwROsyvoq0eRVX0fSSrJ5Ezo72Kh1um4F8YYNUlVhuA",
    "scope": "venue:read venue-booking:create",
    "expires_in": 3600,
    "token_type": "Bearer"
}

๐Ÿ“˜ Field-by-Field Explanation

access_token This is the actual JWT (JSON Web Token) returned by Auth0.

It is used to authenticate requests to your protected API.

Include it in the Authorization header of your requests:

Authorization: Bearer <access_token>

scope Lists the permissions (scopes) granted to this token.

In this example:

venue:read โ€“ allows read access to venue data.

venue-booking:create โ€“ allows creation of bookings.

expires_in Represents the lifetime of the token in seconds.

3600 seconds = 1 hour.

You should always track this value and refresh the token when it's close to expiring.

๐Ÿ”” Important

Do not hardcode the expiration time โ€” always read and store the expires_in value

token_type Indicates how the token should be used.

"Bearer" in this context, meaning:

Authorization: Bearer <access_token>

Example

Java (Java 11+)


import java.net.http.*;
import java.net.URI;
import java.time.Instant;
import java.util.Map;

import com.fasterxml.jackson.databind.ObjectMapper;

public class TokenManager {
    private static final HttpClient client = HttpClient.newHttpClient();
    private static final ObjectMapper mapper = new ObjectMapper();

    private static String accessToken;
    private static Instant expirationTime;

    public static String getAccessToken() throws Exception {
        if (accessToken != null && Instant.now().isAfter(expirationTime.minusSeconds(300))) return accessToken;
        // Refresh token
        String body = """
                    {
                      "grant_type": "client_credentials",
                      "client_id": "YOUR_CLIENT_ID",
                      "client_secret": "YOUR_CLIENT_SECRET",
                      "audience": "api.bookabletech.com"
                    }
                """;

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://bookabletech.uk.auth0.com/oauth/token"))
                .header("Content-Type", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString(body))
                .build();

        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

        var tokenData = mapper.readValue(response.body(), Map.class);
        accessToken = (String) tokenData.get("access_token");
        int expiresIn = (Integer) tokenData.get("expires_in");

        expirationTime = Instant.now().plusSeconds(expiresIn);
        

        return accessToken;
    }
}

C#

using System.Net.Http.Json;
using System.Text.Json;

using System.Net.Http.Json;
using System.Text.Json;

public class TokenManager
{
    private static string? _accessToken;
    private static DateTime _expirationTime;
    private static readonly HttpClient Client = new();

    public static async Task<string> GetAccessTokenAsync()
    {
        if (_accessToken != null && DateTime.UtcNow < _expirationTime.AddMinutes(-5)) return _accessToken!;
        var payload = new
        {
            grant_type = "client_credentials",
            client_id = "YOUR_CLIENT_ID",
            client_secret = "YOUR_CLIENT_SECRET",
            audience = "api.bookabletech.com"
        };

        var response = await Client.PostAsJsonAsync("https://bookabletech.uk.auth0.com/oauth/token", payload);
        var content = await response.Content.ReadAsStringAsync();

        using var doc = JsonDocument.Parse(content);
        _accessToken = doc.RootElement.GetProperty("access_token").GetString();
        var expiresIn = doc.RootElement.GetProperty("expires_in").GetInt32();
        _expirationTime = DateTime.UtcNow.AddSeconds(expiresIn);

        return _accessToken!;
    }
}

Ruby

require 'net/http'
require 'json'
require 'time'

class TokenManager
  @@access_token = nil
  @@expiration_time = Time.now

  def self.get_access_token
    if @@access_token.nil? || Time.now >= (@@expiration_time - 300)
      uri = URI("https://bookabletech.uk.auth0.com/oauth/token")
      request = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')

      request.body = {
        grant_type: 'client_credentials',
        client_id: 'YOUR_CLIENT_ID',
        client_secret: 'YOUR_CLIENT_SECRET',
        audience: 'api.bookabletech.com'
      }.to_json

      response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
        http.request(request)
      end

      data = JSON.parse(response.body)
      @@access_token = data["access_token"]
      @@expiration_time = Time.now + data["expires_in"].to_i
    end

    @@access_token
  end
end