JWT Authentication
Available since: v4.1.0
Harper supports token-based authentication using JSON Web Tokens (JWTs). Rather than sending credentials on every request, a client authenticates once and receives tokens that are used for subsequent requests.
Tokens
JWT authentication uses two token types:
operation_token— Used to authenticate all Harper operations via aBearertokenAuthorizationheader. Default expiry: 1 day.refresh_token— Used to obtain a newoperation_tokenwhen the current one expires. Default expiry: 30 days.
Create Authentication Tokens
Call create_authentication_tokens with your Harper credentials. No Authorization header is required for this operation.
{
"operation": "create_authentication_tokens",
"username": "username",
"password": "password"
}
cURL example:
curl --location --request POST 'http://localhost:9925' \
--header 'Content-Type: application/json' \
--data-raw '{
"operation": "create_authentication_tokens",
"username": "username",
"password": "password"
}'
Response:
{
"operation_token": "<jwt-operation-token>",
"refresh_token": "<jwt-refresh-token>"
}
Using the Operation Token
Pass the operation_token as a Bearer token in the Authorization header on subsequent requests:
curl --location --request POST 'http://localhost:9925' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <operation_token>' \
--data-raw '{
"operation": "search_by_hash",
"schema": "dev",
"table": "dog",
"hash_values": [1],
"get_attributes": ["*"]
}'
Refreshing the Operation Token
When the operation_token expires, use the refresh_token to obtain a new one. Pass the refresh_token as the Bearer token:
curl --location --request POST 'http://localhost:9925' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <refresh_token>' \
--data-raw '{
"operation": "refresh_operation_token"
}'
Response:
{
"operation_token": "<new-jwt-operation-token>"
}
When both tokens have expired, call create_authentication_tokens again with your username and password.
Issuing Tokens from a Custom Resource
Custom Resources can mint tokens programmatically by invoking the same operations via server.operation(). This is useful when you want a Resource-style endpoint (e.g., POST /IssueTokens) instead of (or in addition to) the raw Operations API.
import { Resource, server } from 'harper';
export class IssueTokens extends Resource {
static async get(_target, context) {
// Caller is already authenticated (Basic Auth or an existing JWT) — issue
// tokens for the current user.
const { operation_token, refresh_token } = await server.operation(
{ operation: 'create_authentication_tokens' },
context,
true
);
return { operation_token, refresh_token };
}
static async post(_target, data) {
// Caller provides credentials in the body — issue tokens directly.
const { username, password } = await data;
if (!username || !password) {
return new Response('username and password required', { status: 400 });
}
const { operation_token, refresh_token } = await server.operation({
operation: 'create_authentication_tokens',
username,
password,
});
return { operation_token, refresh_token };
}
}
export class RefreshJWT extends Resource {
static async post(_target, data) {
const { refresh_token } = await data;
if (!refresh_token) {
return new Response('refresh_token required', { status: 400 });
}
const { operation_token } = await server.operation({
operation: 'refresh_operation_token',
refresh_token,
});
return { operation_token };
}
}
Pass authorize: true (third argument) when the operation should run as the current authenticated user; omit it (or pass false) when the operation supplies its own credentials.
Token Expiry Configuration
Token timeouts are configurable in harper-config.yaml under the top-level authentication section:
authentication:
operationTokenTimeout: 1d # Default: 1 day
refreshTokenTimeout: 30d # Default: 30 days
Valid duration string values follow the jsonwebtoken package format (e.g., 1d, 12h, 60m). See Security / Configuration for the full authentication config reference.
When to Use JWT Auth
JWT authentication is preferred over Basic Auth when:
- You want to avoid sending credentials on every request
- Your client can store and manage tokens
- You have multiple sequential requests and want to avoid repeated credential encoding
For simple or server-to-server scenarios, see Basic Authentication.
Security Notes
- Always use HTTPS in production to protect tokens in transit. See HTTP / TLS.
- Store tokens securely; treat them like passwords.
- If a token is compromised, it will remain valid until it expires. Consider setting shorter
operationTokenTimeoutvalues in high-security environments.