Skip to main content

Authentication

Authenticate your applications using OAuth2 Client Credentials flow with JWT tokens.

Overview​

The Huntrecht Platform API uses OAuth 2.0 Client Credentials Grant for server-to-server authentication. This flow is designed for trusted backend applications and provides:

  • Secure token-based authentication
  • Automatic token refresh
  • Scope-based authorization
  • JWT token validation

Authentication Flow​

sequenceDiagram
participant App as Your Application
participant Auth as Huntrecht Auth
participant API as Platform API

App->>Auth: POST /auth/token (client_id + secret)
Auth-->>App: Access Token + Refresh Token
App->>API: GET /users/me (Bearer token)
API-->>App: User Profile Data

Getting Access Tokens​

Request Access Token​

import requests

response = requests.post(
"https://api.huntrecht.com/api/v1/auth/token",
json={
"grant_type": "client_credentials",
"client_id": "hnt_your_client_id",
"client_secret": "your_secret"
}
)

tokens = response.json()
print(tokens)

Response:

{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 1800,
"refresh_token": "refresh_abc123..."
}

Token Expiration​

TokenExpirationAction Required
Access Token30 minutesUse refresh token
Refresh Token30 daysRe-authenticate with credentials

Refresh Access Token​

response = requests.post(
"https://api.huntrecht.com/api/v1/auth/token",
json={
"grant_type": "refresh_token",
"refresh_token": tokens["refresh_token"]
}
)

new_tokens = response.json()

Using Access Tokens​

Include the token in the Authorization header:

headers = {
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
}

response = requests.get(
"https://api.huntrecht.com/api/v1/users/me",
headers=headers
)

User Registration (B2B Onboarding)​

Register a New Customer Account​

response = requests.post(
"https://api.huntrecht.com/api/v1/auth/register",
headers={"Content-Type": "application/json"},
json={
"email": "buyer@company.com",
"password": "secure_password123",
"company_name": "Acme Corporation",
"contact_name": "John Buyer",
"phone": "+1-555-123-4567",
"tax_id": "12-3456789",
"address": {
"street": "123 Business Ave",
"city": "Commerce City",
"state": "CA",
"postal_code": "90210",
"country": "US"
}
}
)

user = response.json()
print(f"User ID: {user['id']}")
print(f"Status: {user['status']}")

Registration Response​

{
"id": "user_abc123",
"email": "buyer@company.com",
"company_name": "Acme Corporation",
"status": "pending_kyc",
"shopify_company_id": null,
"created_at": "2026-01-11T10:00:00Z"
}

Email/Password Login​

Login with Credentials​

response = requests.post(
"https://api.huntrecht.com/api/v1/auth/login",
json={
"email": "buyer@company.com",
"password": "secure_password123"
}
)

tokens = response.json()

Login Response​

{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 1800,
"refresh_token": "refresh_xyz789...",
"user": {
"id": "user_abc123",
"email": "buyer@company.com",
"company_name": "Acme Corporation",
"role": "buyer"
}
}

Google OAuth Login​

Step 1: Redirect to Google​

GET https://huntrecht.com/auth/google

Step 2: Handle Callback​

After user authorizes, Google redirects to your callback URL with a code:

GET https://yourapp.com/callback?code=4/ABCD...

Step 3: Exchange Code for Token​

response = requests.post(
"https://api.huntrecht.com/api/v1/auth/google/callback",
json={"code": "4/ABCD..."}
)

tokens = response.json()

Shopify OAuth Login​

# Step 1: Redirect to Shopify authorization
# GET https://{shop}.myshopify.com/admin/oauth/authorize?
# client_id={client_id}&scope=read_orders,read_customers&redirect_uri={callback}

# Step 2: Exchange code for token
response = requests.post(
"https://api.huntrecht.com/api/v1/auth/shopify/callback",
json={
"shop": "your-store.myshopify.com",
"code": "hacc_abc123..."
}
)

tokens = response.json()

JWT Token Structure​

Decoded JWT payload:

{
"sub": "user_abc123",
"client_id": "hnt_client_xyz",
"scopes": ["orders:read", "orders:write", "subscriptions:read"],
"role": "buyer",
"company_id": "comp_123",
"exp": 1705555200,
"iat": 1705551600
}
ClaimDescription
subUser ID
client_idAPI client identifier
scopesGranted permission scopes
roleUser role (admin, buyer, etc.)
company_idAssociated company/tenant

Security Best Practices​

Security Requirements
  1. Never store credentials in code - Use environment variables
  2. Never expose tokens in URLs - Use headers only
  3. Validate tokens server-side - Never trust client validation
  4. Use HTTPS only - All requests must use TLS
  5. Rotate secrets regularly - Rotate client_secret quarterly
  6. Implement token refresh - Don't require re-authentication

Secure Token Storage​

import os
from cryptography.fernet import Fernet

# Encrypt tokens at rest
cipher = Fernet(os.environ["ENCRYPTION_KEY"])

def store_token(token):
encrypted = cipher.encrypt(token.encode())
# Store encrypted token in database
return encrypted

def retrieve_token(encrypted):
return cipher.decrypt(encrypted).decode()

Token Scopes​

ScopeDescription
orders:readView orders
orders:writeCreate/modify orders
payments:readView payments
payments:writeProcess payments
subscriptions:readView subscriptions
subscriptions:writeManage subscriptions
credit:readView credit scores
credit:writeRequest credit assessments
kyc:readView KYC status
kyc:writeSubmit KYC documents
users:readView user profiles
users:writeModify user profiles

Error Handling​

Error CodeDescriptionSolution
invalid_clientInvalid client_id or secretVerify credentials
invalid_grantExpired/invalid refresh tokenRe-authenticate
unauthorized_clientClient not authorized for scopeRequest correct scopes
invalid_scopeRequested scope not allowedCheck allowed scopes
access_deniedUser denied authorizationUser action required

Session Management​

Get Current User​

response = requests.get(
"https://api.huntrecht.com/api/v1/users/me",
headers={"Authorization": f"Bearer {access_token}"}
)

user = response.json()
print(user)

Update User Profile​

response = requests.put(
"https://api.huntrecht.com/api/v1/users/me",
headers={"Authorization": f"Bearer {access_token}"},
json={
"phone": "+1-555-987-6543",
"address": {
"street": "456 New Street",
"city": "Business City",
"state": "CA",
"postal_code": "90211",
"country": "US"
}
}
)

Logout​

# Revoke refresh token
response = requests.post(
"https://api.huntrecht.com/api/v1/auth/revoke",
json={"refresh_token": refresh_token}
)

Next Steps​