Skip to main content

Overview

BlockDB uses OAuth 2.0 with JWT bearer tokens for API authentication. All requests must include a valid token in the Authorization header. Tokens are scoped to specific datasets, chains, and rate limits.

Authentication Flow

1

Request Access

Contact [email protected] to request API access. Provide:
  • Your organization name
  • Intended use case
  • Required datasets and chains
  • Expected request volume
2

Receive Credentials

You’ll receive:
  • Username and Password for authentication
  • Client ID and Client Secret for token generation
  • Scopes defining your access permissions
  • Rate limits based on your plan
3

Generate JWT Token

Use your credentials to request a JWT token from the UserService authentication endpoint. You can use the Code examples provided below to generate the JWT Access Token.
4

Include in Requests

Send the token in the Authorization header with every API request:
Authorization: Bearer <your_jwt_token>
The token is valid for 15 minutes. For production applications, use a token refresh mechanism that automatically renews tokens before expiration.

Code examples: generate the JWT Access Token

The token is obtained from https://user.blockdb.io/api/authorization/token (OAuth 2.0 Password Credentials, Basic auth for client). Use the Access Token when calling https://api.blockdb.io.
using System.Security.Claims;
using System.Text.Json;
using Duende.IdentityModel.Client;

public class Program
{
    private static string apiBaseUrl = "https://user.blockdb.io/api";
    private static string username = "<USERNAME>";
    private static string password = "<PASSWORD>";
    private static string clientId = "<CLIENT_ID>";
    private static string clientSecret = "<CLIENT_SECRET>";
    private static string scope = "offline_access api";

    public static async Task Main(string[] args)
    {
        var httpClient = CreateHttpClient();

        if (_discoveryDocument == null)
        {
            var discoveryDocument = await httpClient.GetDiscoveryDocumentAsync(apiBaseUrl);
            if (discoveryDocument.IsError)
                throw new InvalidOperationException("Failed to retrieve discovery document.", discoveryDocument.Exception);
            _discoveryDocument = discoveryDocument;
        }

        var tokenResponse = await httpClient.RequestPasswordTokenAsync(new PasswordTokenRequest
        {
            Address = _discoveryDocument.TokenEndpoint,
            ClientId = clientId,
            ClientSecret = clientSecret,
            UserName = username,
            Password = password,
            Scope = scope
        });

        if (tokenResponse.IsError || string.IsNullOrEmpty(tokenResponse.AccessToken))
            throw new InvalidOperationException("Failed to retrieve token." + tokenResponse.Error);

        var userInfoResponse = await httpClient.GetUserInfoAsync(new UserInfoRequest
        {
            Address = _discoveryDocument.UserInfoEndpoint,
            Token = tokenResponse.AccessToken
        });

        if (userInfoResponse.IsError || string.IsNullOrEmpty(userInfoResponse.Raw))
            throw new InvalidOperationException("Failed to retrieve user info.", userInfoResponse.Exception);

        Console.WriteLine("--------------------------------");
        Console.WriteLine("User info: " + userInfoResponse.Raw);
        Console.WriteLine("--------------------------------");
        Console.WriteLine("Access Token: " + tokenResponse.AccessToken);
        Console.WriteLine("--------------------------------");
        Console.WriteLine("Refresh Token: " + tokenResponse.RefreshToken);
    }

    private static HttpClient CreateHttpClient()
    {
        var handler = new HttpClientHandler
        {
            ServerCertificateCustomValidationCallback =
                HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
        };
        return new HttpClient(handler, disposeHandler: true);
    }

    private static DiscoveryDocumentResponse? _discoveryDocument;
}

Code examples: token + refresh + get blocks

Tokens are obtained from https://user.blockdb.io/api/authorization/token (OAuth 2.0 Password Credentials, Basic auth for client). Use the token when calling https://api.blockdb.io. Refresh the token every 15 minutes; the examples use a background task so the main thread can call the API with the current token.
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

const string TokenUrl = "https://user.blockdb.io/api/authorization/token";
const string Scope = "offline_access api";

var clientId = "<BLOCKDB_CLIENT_ID>";
var clientSecret = "<BLOCKDB_CLIENT_SECRET>";
var username = "<BLOCKDB_USERNAME>";
var password = "<BLOCKDB_PASSWORD>";

if (string.IsNullOrEmpty(clientId) || string.IsNullOrEmpty(clientSecret) ||
    string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
{
    Console.WriteLine("Set BLOCKDB_CLIENT_ID, BLOCKDB_CLIENT_SECRET, BLOCKDB_USERNAME, BLOCKDB_PASSWORD");
    return 1;
}

var tokenHolder = new TokenHolder();
using var http = new HttpClient();

var tokens = await RequestPasswordTokenAsync(clientId!, clientSecret!, username!, password!);
if (tokens == null) { Console.WriteLine("Failed to get initial token."); return 1; }
tokenHolder.Set(tokens.Value.AccessToken!, tokens.Value.RefreshToken!);

// Background: refresh token every 14 minutes (refresh_token grant, fallback to password)
_ = Task.Run(async () =>
{
    while (true)
    {
        await Task.Delay(TimeSpan.FromMinutes(14));
        try
        {
            var refreshToken = tokenHolder.GetRefreshToken();
            TokenResult? newTokens = null;
            if (!string.IsNullOrEmpty(refreshToken))
                newTokens = await RequestRefreshTokenAsync(clientId!, clientSecret!, refreshToken);
            if (newTokens == null && !string.IsNullOrEmpty(username))
                newTokens = await RequestPasswordTokenAsync(clientId!, clientSecret!, username!, password!);
            if (newTokens != null)
                tokenHolder.Set(newTokens.Value.AccessToken, newTokens.Value.RefreshToken ?? refreshToken ?? "");
        }
        catch (Exception ex) { Console.WriteLine("Token refresh failed: " + ex.Message); }
    }
});

// Main: get blocks every 1 min
while (true)
{
    var response = await GetBlocksAsync(http, tokenHolder.GetAccessToken());
    response.EnsureSuccessStatusCode();
    Console.WriteLine($"[{DateTime.UtcNow:yyyy-MM-dd HH:mm:ss} UTC] {await response.Content.ReadAsStringAsync()}");
    await Task.Delay(TimeSpan.FromMinutes(1));
}

static async Task<TokenResult?> RequestPasswordTokenAsync(string clientId, string clientSecret, string username, string password)
{
    var body = new FormUrlEncodedContent(new[]
    {
        new KeyValuePair<string, string>("grant_type", "password"),
        new KeyValuePair<string, string>("username", username),
        new KeyValuePair<string, string>("password", password),
        new KeyValuePair<string, string>("scope", Scope)
    });
    return await PostTokenRequestAsync(clientId, clientSecret, body);
}

static async Task<TokenResult?> RequestRefreshTokenAsync(string clientId, string clientSecret, string refreshToken)
{
    var body = new FormUrlEncodedContent(new[]
    {
        new KeyValuePair<string, string>("grant_type", "refresh_token"),
        new KeyValuePair<string, string>("refresh_token", refreshToken)
    });
    return await PostTokenRequestAsync(clientId, clientSecret, body);
}

static async Task<TokenResult?> PostTokenRequestAsync(string clientId, string clientSecret, HttpContent body)
{
    var credentials = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{clientId}:{clientSecret}"));
    using var tokenClient = new HttpClient();
    tokenClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", credentials);
    var res = await tokenClient.PostAsync(TokenUrl, body);
    if (!res.IsSuccessStatusCode) return null;
    var json = await res.Content.ReadAsStringAsync();
    var doc = JsonDocument.Parse(json);
    var root = doc.RootElement;
    var accessToken = root.TryGetProperty("access_token", out var at) ? at.GetString() : null;
    var refreshToken = root.TryGetProperty("refresh_token", out var rt) ? rt.GetString() : null;
    if (string.IsNullOrEmpty(accessToken)) return null;
    return new TokenResult(accessToken, refreshToken);
}

static async Task<HttpResponseMessage> GetBlocksAsync(HttpClient http, string token)
{
    var req = new HttpRequestMessage(HttpMethod.Post, "https://api.blockdb.io/v1/evm/raw/blocks");
    req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
    req.Content = new StringContent("{\"chain_id\":1,\"from_block\":12345678,\"to_block\":12345999,\"limit\":10}", Encoding.UTF8, "application/json");
    return await http.SendAsync(req);
}

readonly record struct TokenResult(string AccessToken, string? RefreshToken);

class TokenHolder
{
    private string _accessToken = "";
    private string _refreshToken = "";
    private readonly object _lock = new();
    public void Set(string accessToken, string refreshToken) { lock (_lock) { _accessToken = accessToken; _refreshToken = refreshToken ?? ""; } }
    public string GetAccessToken() { lock (_lock) { return _accessToken; } }
    public string GetRefreshToken() { lock (_lock) { return _refreshToken; } }
}

See Also

curl -X POST 'https://api.blockdb.io/v1/evm/raw/blocks' \
  -H 'Authorization: Bearer <Access Token from the previous example>' \
  -H 'Content-Type: application/json' \
  -d '{
    "chain_id": 1,
    "from_block": 12345678,
    "to_block": 12345999
  }'
{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Invalid or expired token",
    "details": "Token expired at 2025-01-15T10:30:00Z"
  }
}