Skip to content

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

VerbPathAuthDescription
POST/v1/registerpublicRegister a new user account
POST/v1/authpasswordLog in with username + password; creates a token and sets a session cookie
POST/v1/tokentoken or passwordCreate a new named API token; the token value is returned in the response
GET/v1/tokentokenVerify credentials; returns 200 if the token is valid
POST/v1/logouttokenInvalidate 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.

VerbPathAuthDescription
POST/v1/admin/challengepublicAnswer a challenge by its uid (knowing the uid from the e-mail is the proof, so no token is required)

Who am I

VerbPathDescription
GET/v1/whoamiThe 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.

VerbPathDescription
GET/v1/admin/tokensList your tokens
GET/v1/admin/tokens/:tokenA token's folder
GET/v1/admin/tokens/:token/infoToken metadata: name, creation time, expiry, last use
GET/v1/admin/tokens/:token/logThat token's activity log
DELETE/v1/admin/tokens/:tokenRevoke 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.