A 401 from Apiker itself, rather than from your handler, has a small number of causes. Work through them in this order.
The caller is banned
The ban check runs before your handler and answers 401 with an empty body. Bans never expire, so one added during testing stays until you lift it.
import { isEntityBanned, unbanEntity, getSignedIp } from "apiker";
await isEntityBanned(getSignedIp());
await unbanEntity(getSignedIp());If the firewall is enabled, crossing its per-minute threshold bans you automatically — which is easy to do while load testing.
The token is bound to another device
Tokens carry a hash of the caller's IP and User-Agent, and it is verified on every read. A token copied from a browser into curl, or used after your address changed, is rejected.
The token expired
Access tokens last 30 minutes. Exchange the refresh token at /auth/refresh for a new pair — refresh tokens do not expire.
The secret changed
Every token is signed with APIKER_SECRET_KEY. If it was regenerated — for instance because .env was recreated — all existing tokens fail verification and everyone has to sign in again.


