Blnk provides two authentication methods: a master key for full access and scoped API keys for granular permissions. This guide shows you how to manage authentication and implement secure access control.
Authentication methods
Master key
The master key provides unrestricted access to all Blnk API endpoints. It’s configured in your blnk.json file:
{
"server" : {
"secret_key" : "your-secure-master-key-here" ,
"secure" : true
}
}
Keep your master key secret! Never commit it to version control or share it publicly.
API keys
API keys provide scoped access with specific permissions. They’re ideal for:
Third-party integrations
Mobile applications
Microservices
Client-facing APIs
Using the master key
Include the master key in the X-Blnk-Key header:
curl -X POST https://api.yourapp.com/transactions \
-H "X-Blnk-Key: your-master-key" \
-H "Content-Type: application/json" \
-d '{
"amount": 100.00,
"currency": "USD",
"source": "bln_source",
"destination": "bln_dest"
}'
The master key grants access to all endpoints.
Creating API keys
Generate scoped API keys for limited access:
Create API key with scopes
POST /api-keys
X-Blnk-Key: your-master-key
{
"name" : "Mobile App Key" ,
"owner_id" : "app_mobile_v1" ,
"scopes" : [
"transactions:read" ,
"transactions:write" ,
"balances:read"
],
"expires_at" : "2025-12-31T23:59:59Z"
}
Response with API key
{
"api_key_id" : "key_abc123xyz" ,
"key" : "blnk_sk_1234567890abcdef" ,
"name" : "Mobile App Key" ,
"owner_id" : "app_mobile_v1" ,
"scopes" : [
"transactions:read" ,
"transactions:write" ,
"balances:read"
],
"expires_at" : "2025-12-31T23:59:59Z" ,
"created_at" : "2024-01-15T10:00:00Z" ,
"active" : true
}
The key field is only returned once during creation. Store it securely!
Use API key in requests
curl -X GET https://api.yourapp.com/balances/bln_123 \
-H "X-Blnk-Key: blnk_sk_1234567890abcdef"
Available scopes
API keys use resource:action format for permissions:
Transaction scopes
transactions:read View transactions and transaction details
transactions:write Create and record new transactions
Balance scopes
balances:read View balance information
balances:write Create new balances
Account scopes
accounts:read View account information
accounts:write Create and modify accounts
Ledger scopes
ledgers:read View ledger information
ledgers:write Create and modify ledgers
Identity scopes
identities:read View identity information
identities:write Create and modify identities
Monitor scopes
balance-monitors:read View balance monitors
balance-monitors:write Create and manage monitors
Reconciliation scopes
reconciliation:read View reconciliation data
reconciliation:write Start and manage reconciliations
Other scopes
hooks:read View webhook configurations
hooks:write Create and manage webhooks
api-keys:read View API keys (own keys only)
api-keys:write Create and revoke API keys
search:read Search across resources
metadata:write Update metadata on resources
Managing API keys
List all API keys
GET /api-keys?owner_id=app_mobile_v1
X-Blnk-Key: your-master-key
[
{
"api_key_id" : "key_abc123xyz" ,
"name" : "Mobile App Key" ,
"owner_id" : "app_mobile_v1" ,
"scopes" : [
"transactions:read" ,
"balances:read"
],
"expires_at" : "2025-12-31T23:59:59Z" ,
"created_at" : "2024-01-15T10:00:00Z" ,
"last_used" : "2024-01-16T14:30:00Z" ,
"active" : true
}
]
Revoke an API key
DELETE /api-keys/key_abc123xyz
X-Blnk-Key: your-master-key
{
"message" : "API key revoked successfully"
}
Revoked keys immediately stop working.
Common API key configurations
Read-only access
For analytics and reporting:
POST /api-keys
{
"name" : "Analytics Dashboard" ,
"owner_id" : "dashboard_analytics" ,
"scopes" : [
"transactions:read" ,
"balances:read" ,
"accounts:read" ,
"search:read"
],
"expires_at" : "2025-12-31T23:59:59Z"
}
Mobile app key
For customer-facing mobile applications:
POST /api-keys
{
"name" : "Customer Mobile App" ,
"owner_id" : "app_mobile_customer" ,
"scopes" : [
"transactions:read" ,
"transactions:write" ,
"balances:read"
],
"expires_at" : "2025-12-31T23:59:59Z"
}
Third-party integration
For payment processor integration:
POST /api-keys
{
"name" : "Stripe Integration" ,
"owner_id" : "integration_stripe" ,
"scopes" : [
"transactions:write" ,
"transactions:read" ,
"balances:read" ,
"reconciliation:write"
],
"expires_at" : "2025-12-31T23:59:59Z"
}
Webhook management key
For managing webhooks only:
POST /api-keys
{
"name" : "Webhook Manager" ,
"owner_id" : "service_webhook_manager" ,
"scopes" : [
"hooks:read" ,
"hooks:write"
],
"expires_at" : "2025-12-31T23:59:59Z"
}
When using API keys, Blnk automatically adds the key ID to transaction metadata:
// Request with API key
POST /transactions
X-Blnk-Key: blnk_sk_abc 123
{
"amount" : 100.00 ,
"source" : "bln_source" ,
"destination" : "bln_dest"
}
// Blnk automatically injects:
{
"amount" : 100.00 ,
"source" : "bln_source" ,
"destination" : "bln_dest" ,
"meta_data" : {
"BLNK_GENERATED_BY" : "key_abc123xyz"
}
}
This helps with audit trails and tracking which API key created each transaction.
Implementation code (from api/middleware/auth.go:181-270)
How Blnk authenticates requests:
func ( m * AuthMiddleware ) Authenticate () gin . HandlerFunc {
return func ( c * gin . Context ) {
// Skip auth for health endpoints
if c . Request . URL . Path == "/" || c . Request . URL . Path == "/health" {
c . Next ()
return
}
// Check if secure mode is enabled
conf , err := config . Fetch ()
if err == nil && conf != nil && ! conf . Server . Secure {
c . Next ()
return
}
key := extractKey ( c )
if key == "" {
c . JSON ( 401 , gin . H { "error" : "Authentication required. Use X-Blnk-Key header" })
c . Abort ()
return
}
// Check if it's the master key
if err == nil && conf != nil && conf . Server . SecretKey == key {
c . Set ( "isMasterKey" , true )
c . Next ()
return
}
// Try API key authentication
apiKey , err := m . service . GetAPIKeyByKey ( c . Request . Context (), key )
if err != nil {
c . JSON ( 401 , gin . H { "error" : "Invalid API key" })
c . Abort ()
return
}
if ! apiKey . IsValid () {
c . JSON ( 401 , gin . H { "error" : "API key is expired or revoked" })
c . Abort ()
return
}
// Determine required resource from path
resource := getResourceFromPath ( c . Request . URL . Path )
if resource == "" {
c . JSON ( 403 , gin . H { "error" : "Unknown resource type" })
c . Abort ()
return
}
// Check if API key has permission
if ! HasPermission ( apiKey . Scopes , resource , c . Request . Method ) {
action := methodToAction [ c . Request . Method ]
c . JSON ( 403 , gin . H { "error" : "Insufficient permissions for " + string ( resource ) + ":" + string ( action )})
c . Abort ()
return
}
// Inject API key ID into metadata for POST requests
if c . Request . Method == "POST" && c . Request . Body != nil {
if err := injectAPIKeyToMetadata ( c , apiKey . APIKeyID ); err != nil {
logrus . Error ( "Failed to inject API key ID into metadata:" , err )
}
}
// Update last used timestamp
go func () {
_ = m . service . UpdateLastUsed ( c . Request . Context (), apiKey . APIKeyID )
}()
c . Set ( "apiKey" , apiKey )
c . Next ()
}
}
Disabling authentication
For development or internal deployments, you can disable authentication:
{
"server" : {
"secure" : false
}
}
Never disable authentication in production! This exposes your entire API.
Best practices
Rotate keys regularly Create new API keys and revoke old ones periodically
Use least privilege Grant only the minimum scopes needed for each integration
Set expiry dates Always set expiration dates for API keys
Monitor key usage Track last_used timestamps to identify unused keys
Revoke immediately Revoke compromised keys immediately
Store securely Use environment variables or secret managers for keys
Handling authentication errors
Missing authentication
{
"error" : "Authentication required. Use X-Blnk-Key header"
}
Solution : Include X-Blnk-Key header in all requests.
Invalid API key
{
"error" : "Invalid API key"
}
Solution : Verify the key is correct and hasn’t been revoked.
Expired API key
{
"error" : "API key is expired or revoked"
}
Solution : Create a new API key or extend the expiration date.
Insufficient permissions
{
"error" : "Insufficient permissions for transactions:write"
}
Solution : Update the API key scopes or use a key with appropriate permissions.
Environment-specific keys
Use different API keys for each environment:
# Development
export BLNK_API_KEY = "blnk_sk_dev_1234567890"
# Staging
export BLNK_API_KEY = "blnk_sk_staging_abcdefgh"
# Production
export BLNK_API_KEY = "blnk_sk_prod_xyz7890abc"
SDK authentication examples
Node.js
const axios = require ( 'axios' );
const blnkClient = axios . create ({
baseURL: 'https://api.yourapp.com' ,
headers: {
'X-Blnk-Key' : process . env . BLNK_API_KEY
}
});
// Use the client
const response = await blnkClient . post ( '/transactions' , {
amount: 100.00 ,
source: 'bln_source' ,
destination: 'bln_dest'
});
Python
import os
import requests
class BlnkClient :
def __init__ ( self ):
self .base_url = 'https://api.yourapp.com'
self .headers = {
'X-Blnk-Key' : os.environ[ 'BLNK_API_KEY' ]
}
def create_transaction ( self , data ):
response = requests.post(
f ' { self .base_url } /transactions' ,
json = data,
headers = self .headers
)
return response.json()
# Use the client
client = BlnkClient()
result = client.create_transaction({
'amount' : 100.00 ,
'source' : 'bln_source' ,
'destination' : 'bln_dest'
})
package main
import (
" bytes "
" encoding/json "
" net/http "
" os "
)
type BlnkClient struct {
BaseURL string
APIKey string
Client * http . Client
}
func NewBlnkClient () * BlnkClient {
return & BlnkClient {
BaseURL : "https://api.yourapp.com" ,
APIKey : os . Getenv ( "BLNK_API_KEY" ),
Client : & http . Client {},
}
}
func ( c * BlnkClient ) CreateTransaction ( data map [ string ] interface {}) error {
body , _ := json . Marshal ( data )
req , _ := http . NewRequest ( "POST" , c . BaseURL + "/transactions" , bytes . NewBuffer ( body ))
req . Header . Set ( "X-Blnk-Key" , c . APIKey )
req . Header . Set ( "Content-Type" , "application/json" )
resp , err := c . Client . Do ( req )
if err != nil {
return err
}
defer resp . Body . Close ()
return nil
}
Security checklist
Next steps
Webhooks Secure your webhook endpoints with API keys
Wallet Management Start building with authenticated API requests