Skip to content

Latest commit

 

History

History
52 lines (34 loc) · 3.16 KB

File metadata and controls

52 lines (34 loc) · 3.16 KB
title Authentication
description API keys, session JWTs and team scoping.

Every request to every service authenticates with one header:

Authorization: Bearer <token>

Two token kinds are accepted, and the server tells them apart by shape.

API keys (recommended for integrations)

An API key is an opaque bearer token of the form gtm_live_ plus 40 characters. There is no OAuth handshake: you paste it into your runtime and send it as the bearer token on every call.

  • The secret is shown once. POST /api/api-keys returns the full token in plaintext_token in that one response. Afterwards the API returns only token_prefix and token_last4 for display. The server stores a SHA-256 hash, not the key.
  • Rotation replaces the secret. POST /api/api-keys/{sid}/rotate mints a new gtm_live_ secret for the same key record and invalidates the old one. Rotate on any suspicion of a leak, or on a schedule.
  • Keys expire. Default expiry is 3 years from creation; pass expires_at: null on create for a perpetual key.
  • Keys carry permissions. A key created by another key can only hold a subset of the parent's permissions. Downscoping is allowed, escalation is a forbidden error.
  • Keys are team-scoped. A key belongs to the team it was created in and acts on that team's data.
  • A key is not a person. It authenticates as itself, with its own permissions, so no user account sits behind it. GET /api/users/current (get_current_user) therefore answers 403 with context.reason: not_a_user_actor on a key, and no permission you add to the key changes that: the profile that endpoint returns belongs to a signed-in person. Sign in, or connect through OAuth, when you actually need it.

Manage keys in the app or over the ID and Teams API: search them for an access audit (last_used_at shows stale keys worth revoking), check expires_at for keys about to lapse, and revoke what you no longer use.

Session JWTs

Signing in to app.gtm-api.com issues a short-lived JWT. It goes in the same Authorization: Bearer header. This is what the app itself uses; for server-to-server integrations prefer an API key, which does not expire mid-job.

The Team-SID header

A token is normally already scoped to one team, and that scope is authoritative. The optional Team-SID header exists for tokens that do not carry a team: it selects which of your teams the call acts on.

Team-SID: ts_tm_Hx7kQ3mN2pL4

When the token already names a team, Team-SID is ignored. With an API key you can leave it out entirely.

Auth failures

Code HTTP Meaning
unauthorized 401 Missing, expired, revoked or malformed token
forbidden 403 Valid token, but no rights on this team or resource

Both arrive as the standard error envelope, so they are machine-readable like every other failure.

Handling the secret

Treat gtm_live_ tokens like passwords: keep them in a secret manager or environment variable, never in client-side code or a repository, and never in logs. If a key leaks, rotate it; the old secret stops working immediately.