Authentication
Sphere uses a two-step authentication flow: first resolve the user's tenant via the Hub, then authenticate against the sphere instance to obtain JWT tokens. All API requests require a valid access_token in the Authorization header.
Hub discovery flow
Before authenticating, you must resolve which sphere instance hosts the user's tenant. The Hub is a centralized discovery service that maps a user login (email) to a sphere URL.
Send the user's email to the Hub's resolve endpoint. The response tells you which sphere instance to authenticate against.
This step is required because Sphere is a distributed platform — tenants can be hosted on different sphere instances. The Hub acts as the single entry point for all users.
The Hub runs on a separate gateway (port 81 in development). In production, it has its own domain (e.g., hub.example.com).
curl -X POST https://hub.example.com/api/v1/hub/resolve-login \
-H "Content-Type: application/json" \
-d '{"login": "user@acme.local"}'
JWT RS256 tokens
Sphere uses RS256 (RSA Signature with SHA-256) for signing JWT tokens. This means tokens are signed with a private key on sphere-auth and can be verified by any service holding the public key — no shared secret needed.
Each successful login returns two tokens:
- Name
access_token- Type
- string
- Description
A short-lived JWT (60 minutes) used to authenticate API requests. Include it in the
Authorizationheader.
- Name
refresh_token- Type
- string
- Description
A long-lived opaque token (30 days) used to obtain a new
access_tokenwhen the current one expires.
Using the access token
curl https://your-sphere.example.com/core/api/v1/families \
-H "Authorization: Bearer {access_token}"
Never include the refresh_token in the Authorization header. It is only used with the /auth/api/v1/auth/refresh endpoint.
Token claims
The JWT access_token contains claims that identify the user and their tenant context. Every service in the platform reads these claims to scope the request.
- Name
user_id- Type
- string (UUID)
- Description
The unique identifier of the authenticated user.
- Name
tenant_id- Type
- string (UUID)
- Description
The unique identifier of the tenant. Used internally for database isolation.
- Name
tenant_short_id- Type
- string
- Description
A short human-readable tenant identifier (slug).
- Name
workspace_id- Type
- string (UUID)
- Description
The active workspace identifier. Determines RBAC permissions.
- Name
token_type- Type
- string
- Description
The type of token:
user,guest,agent, orinternal-service.
- Name
scopes- Type
- array of strings
- Description
The permissions granted to this token.
Decoded JWT payload
{
"user_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
"tenant_id": "a7c8e9f0-1234-5678-abcd-ef0123456789",
"tenant_short_id": "acme",
"workspace_id": "c3d4e5f6-7890-1234-abcd-567890abcdef",
"token_type": "user",
"scopes": ["*"],
"iat": 1708800000,
"exp": 1708803600
}
Multi-tenant context
Every API request in Sphere is scoped to a single tenant. The tenant is determined by the JWT token — there is no need to pass a tenant ID as a query parameter or header.
Each tenant has its own isolated PostgreSQL database. When a request arrives, the platform reads the tenant_id from the JWT, connects to the correct database, and executes the query. This provides full data isolation between tenants.
You cannot access data from another tenant using a given token. If you need to work with multiple tenants, you must authenticate separately for each one.
Token scopes
Tokens are issued with a token_type that determines the level of access:
- Name
user- Type
- token_type
- Description
Standard user token. Has full access to the APIs scoped to the user's workspace roles and permissions.
- Name
guest- Type
- token_type
- Description
Limited access token for external users. Restricted to a subset of endpoints.
- Name
agent- Type
- token_type
- Description
Bot or automation token. Used for service accounts and automated workflows.
- Name
internal-service- Type
- token_type
- Description
Used exclusively for service-to-service communication. Not issued to end users.
Check your token type
# Decode the JWT payload (base64)
echo "eyJhbGciOi..." | cut -d. -f2 | base64 -d | jq .token_type
# → "user"
Token refresh flow
When the access_token expires (after 60 minutes), use the refresh_token to obtain a new token pair. The old refresh token is invalidated and a new one is returned (token rotation).
- Name
refresh_token- Type
- string
- Description
The refresh token from the last login or refresh response.
If the refresh token is expired or invalid, the user must log in again.
curl -X POST https://your-sphere.example.com/auth/api/v1/auth/refresh \
-H "Content-Type: application/json" \
-d '{"refresh_token": "def50200a1b2c3d4..."}'
Service-to-service authentication (HMAC)
Internal communication between Sphere services (e.g., sphere-auth calling sphere-core during tenant provisioning) uses HMAC signatures rather than JWT tokens. This is an internal mechanism — you do not need to implement HMAC as an API consumer.
Each service shares a secret key and signs requests with an HMAC-SHA256 signature in the X-Sphere-Signature header. The receiving service verifies the signature before processing the request.
HMAC authentication is for inter-service calls only. All client-facing API requests must use JWT Bearer tokens.