Authentication
Almost every novem endpoint needs a bearer token. This page covers how you get one, how to manage your tokens, and the handful of public endpoints that don't require auth.
AI-assisted, human-approvednovem uses AI to review and keep our documentation up to date.
The novem API authenticates with a bearer token. You send it on every
request as an Authorization: Bearer <token> header (the CLI and Python
library do this for you once you've logged in). A few endpoints (registration,
login, and the e-mail challenge) are public so that you can create an account
and obtain a token.
Every path below also answers OPTIONS with the verbs valid for your token.
Getting a token
| Verb | Path | Auth | Description |
|---|---|---|---|
POST | /v1/register | public | Register a new user account |
POST | /v1/auth | password | Log in with username + password; creates a token and sets a session cookie |
POST | /v1/token | token or password | Create a new named API token; the token value is returned in the response |
GET | /v1/token | token | Verify credentials; returns 200 if the token is valid |
POST | /v1/logout | token | Invalidate the current session |
The password routes read username and password from the JSON body. They do
not accept an HTTP Basic header: the API reads a Basic password only as a
token, so curl -u you:password is rejected with a 401. To create a token
from a token you already have, send it as a bearer header and leave the
username and password out of the body.
Note: the token value is shown once, when it's created. Store it
somewhere safe. You can't read it back later, only revoke it and issue a new
one. The CLI keeps it for you in ~/.config/novem/novem.conf.
Giving a token an expiry
By default a token lasts until you revoke it. POST /v1/token takes two optional
fields to bound it instead. Supply at most one of them; supplying both is
rejected with a 400.
expires_in— a duration from now: either an integer number of seconds, or a string like"24 hours"or"7 days".expires_on— an absolute timestamp, e.g."2026-09-01T12:00:00Z".
curl -H "Authorization: Bearer $NOVEM_TOKEN" https://api.novem.io/v1/token \
-H "Content-Type: application/json" \
-d '{"token_name": "ci-deploy",
"token_description": "deploy pipeline",
"expires_in": "7 days"}'
The response echoes the resulting expires_on as a UTC ISO timestamp, or null
for a token that never expires:
{
"status": "Success",
"token": "novem_...",
"token_name": "ci-deploy",
"expires_on": "2026-08-25T09:14:03Z"
}
The expiry has to be a finite moment in the future. A past timestamp, a zero or
negative duration, and infinity are all rejected with a 400. Omit both fields to create a token without an expiry.
The e-mail challenge
Some flows (registering, or verifying an e-mail address) send a code or link to your inbox and ask you to prove you received it.
| Verb | Path | Auth | Description |
|---|---|---|---|
POST | /v1/admin/challenge | public | Answer a challenge by its uid (knowing the uid from the e-mail is the proof, so no token is required) |
Who am I
| Verb | Path | Description |
|---|---|---|
GET | /v1/whoami | The user the current token authenticates as; useful for confirming which account a token belongs to |
Managing your tokens
Your tokens live under /v1/admin/tokens, addressed by name. This is where you
audit and revoke them, for instance to roll a token that may have leaked or to
clean up ones you no longer use.
| Verb | Path | Description |
|---|---|---|
GET | /v1/admin/tokens | List your tokens |
GET | /v1/admin/tokens/:token | A token's folder |
GET | /v1/admin/tokens/:token/info | Token metadata: name, creation time, expiry, last use |
GET | /v1/admin/tokens/:token/log | That token's activity log |
DELETE | /v1/admin/tokens/:token | Revoke the token |
Every token in the list carries an expires_on, null if it never expires.
Application connections
Connecting an OAuth application creates a dedicated bearer token for that connection. New connections have a fixed maximum lifetime of 30 days, or less when the credential that approved them expires sooner. Refreshing the connection does not extend that deadline.
Settings → Tokens lists your connected applications, grouped by the application each connection was granted to. Choose Disconnect to revoke a single connection, or Disconnect all to revoke every connection from that application. Neither signs you out or touches connections from other applications. Connections made before Novem recorded the application are listed as ungrouped and are disconnected one at a time.
Connections created before the fixed-lifetime policy may still have no absolute deadline. Disconnect and reconnect them to adopt the 30-day bound.
Connecting an application of your own
An application identifies itself to Novem in one of two ways. It can register
once with POST /oauth/register, listing its redirect_uris, and keep the
client_id it is given, or it can
use as its client_id the https URL of a small JSON document it hosts — an
OAuth Client ID Metadata Document, which is what current MCP clients prefer.
Novem fetches that document, checks that the client_id inside it is the URL
itself, and treats it as the registration:
{
"client_id": "https://app.example.com/oauth/client.json",
"client_name": "Example App",
"redirect_uris": ["https://app.example.com/oauth/callback"],
"token_endpoint_auth_method": "none"
}
The consent screen then names the application and the host it returns the
person to, plus the domain that serves the document when that is a different
host; the domain is the part Novem verified. A document may declare
private_key_jwt and publish its keys (jwks or jwks_uri); Novem then
requires a signed assertion on every code exchange and refresh. Redirect URIs
follow the same rules as registration: https, or http://localhost for a
local client. The out-of-band value urn:ietf:wg:oauth:2.0:oob is reserved for
Novem's own clients and refused for any other. The authorization server metadata at
/.well-known/oauth-authorization-server/mcp lists what is supported.
Expired tokens stay in the list
Expired tokens no longer authenticate requests, but remain listed until you
DELETE them. The listing preserves their name, permissions, and expiry date.
Note: a token in your listing is not necessarily a token that works. Check
expires_on against the clock, or read the Expired field on the token's
info card.
/v1/admin/tokens/:token/info still answers for a lapsed token, and it reports
the two states separately:
Expires on: 2026-08-01 09:14
Active: Yes
Expired: Yes
Active: No means you revoked it. Expired: Yes means it ran out on its own.
Both return 401 when used for authentication.
See also
- API overview — the request shape, verbs and permissions.
- Terminology — usernames, FQNPs and shortnames.
- Profile — your account's identity and settings.