Security model
Every endpoint requires authentication unless it is explicitly public, such as sign-up, the plan list and the forgot-password request. Callers are authenticated at the gateway, and what it establishes (the tenant, the user or API key, and the permissions) is what the services check. The identity service also validates user tokens itself.
Sign-in and sessions
Section titled “Sign-in and sessions”Users sign in with their email address and password and receive standard OAuth tokens:
- Short-lived access tokens. An access token is signed by jtWMS and lasts 15 minutes by default. The gateway checks it on every request.
- Rotating refresh tokens. A refresh token renews the session for up to 14 days from its last use by default. Each refresh redeems the token and issues a new one, and re-reads the user, so a renewed session carries the user’s current permissions and a deactivated user can’t renew.
- Revocation. Signing out revokes the refresh token. When a user’s access changes (their roles
change, a role’s permissions change, they are deactivated, or their password is reset), jtWMS ends
their existing access tokens at once: the next request gets
401 token_revoked. A password reset also ends their refresh tokens.
Passwords must be at least 10 characters, with an upper-case letter, a lower-case letter, a digit and a symbol, and are stored only as salted one-way hashes. A failed sign-in doesn’t say whether the email or the password was wrong, and a forgot-password request gets the same answer whether or not the address has an account. Reset links are single use and expire after an hour by default, and forgot-password sends a user at most three of them an hour by default.
See Authentication and Getting started.
API keys
Section titled “API keys”API keys give other systems access to one tenant without a user:
- Hashed at rest. jtWMS shows a key once, when it is created, and stores only a hash of it. A lost key can’t be recovered, only replaced.
- Scoped. A key holds a fixed set of permissions chosen when it is created, and can do nothing else. A key can also be given an expiry date.
- Revocable. Revoking a key stops it working within about a minute. A revoked key can’t be restored.
- Attributable. Changes made with a key are recorded in the audit trail against that key.
- Limited to data. Keys work on the warehouse configuration, catalog and webhook APIs. The identity endpoints (users, roles, invitations, API keys, the tenant and its plan) accept only a signed-in user.
The number of keys a tenant can hold depends on its plan. See API keys.
Permissions and roles
Section titled “Permissions and roles”Access is controlled by permissions, such as catalog.products.manage. Each permission names a
service, a resource and an action, and a resource’s .manage permission includes its .read.
Every warehouse configuration, catalog and webhook endpoint names the permission it needs, and so
does every change a signed-in user makes to the team, its roles, its API keys or the tenant’s plan.
A caller without the permission gets 403 Forbidden. Any signed-in member of a tenant can read its
team list, its roles and the list of permissions.
Users get permissions through roles. Every tenant has four standard roles (Tenant Admin, Warehouse Manager, Operator and Read-Only API Client) that can’t be edited or deleted, and can build its own roles from any registered permissions. Authorisation is always decided by permissions, never by a role’s name.
Grant only what you hold
Section titled “Grant only what you hold”A user can’t give a person or a key access they don’t have themselves. When a user assigns roles, sends an invitation, adds permissions to a role or creates an API key, every permission being granted must be one they hold, checked against their current permissions in the database rather than their token. Otherwise the request is refused and nothing changes. Removing access is never restricted this way. Two cases are not checked: platform super-admins are exempt, and copying a role copies all of its permissions whatever the copier holds (assigning the copy is still checked).
See Permissions and scopes and Team.
Audit trail
Section titled “Audit trail”Each service records an audit entry for every change to the records a tenant manages, such as facilities, products, users, roles, API keys and webhook subscriptions. Each entry holds:
- who: the user or API key, anonymous for public actions such as sign-up, or the system itself for background work;
- what: the kind of record, its ID and the action;
- before and after: the record’s full state on each side of the change;
- when, and the request’s correlation ID.
Entries are written in the same transaction as the change, so a change is never saved without its entry, and a failed write leaves none. Passwords, key and token hashes, webhook secrets and carrier API keys are never included. Each service keeps its own entries in its own database, and every entry belongs to one tenant. The warehouse configuration trail and the team and access trail can be read through the API, by callers with the matching permission. See Correlation IDs.
Rate limits
Section titled “Rate limits”Each tenant is held to a burst limit, shared by all its users and keys, and a daily request quota
set by its plan. Requests over a limit get 429 Too Many Requests with a Retry-After header. See
Rate limits and feature gates.
If the store behind rate limits and session revocation is unavailable, the gateway lets requests through rather than refusing them. Rate limits aren’t applied, and no session end is checked: any access token that hasn’t expired is accepted, including one whose session was ended before the outage, until it expires (within 15 minutes by default). Session ends triggered during the outage aren’t recorded at all. Token signatures and permission checks still apply. New sign-ins and session renewals fail while the store is down, so a signed-in user’s session ends when their access token expires.
Webhooks
Section titled “Webhooks”- Signed. Every delivery carries an HMAC-SHA256 signature over its timestamp and body, made with the subscription’s secret, so a receiver can check it came from jtWMS unaltered.
- Secrets encrypted at rest. Signing secrets are stored encrypted and shown in full only when created or rotated. Rotating a secret takes effect at once.
- HTTPS targets only. Outside development, a subscription’s URL must use HTTPS and name a public host. Addresses on private, loopback or internal networks are refused, and the address a host resolves to is checked again on every delivery.
See Webhooks.
Carrier credentials
Section titled “Carrier credentials”A tenant ships with its own carrier account and its own API key: carrier contracts and label billing stay the shipper’s.
- Write-only. An API key is accepted when an account is added or changed, and never returned. The API shows only whether the account holds one, and its last four characters.
- Encrypted at rest, per tenant. Keys are stored encrypted, under a key bound to their tenant, so one tenant’s stored key can’t be read as another’s. They are decrypted only for the call to the carrier.
- Kept out of the trail. Neither the key nor its encrypted form is ever included in an audit entry.
Inside the platform
Section titled “Inside the platform”- Services trust the identity information the gateway forwards, so they must not be reachable except through the gateway, which strips any identity information a caller sends.
- The endpoints services use to talk to each other are not routed by the gateway, and require a separate internal key.
- Error responses never include internal exception details outside development; each carries a correlation ID for support instead. See Errors.