Concepts
Team and API keys
How people sign in to the console, what owners and members can do, and how API keys work.
In Temper, a developer is your team or company: environments, policies, credentials, limits and API keys all belong to it. People
on the team sign in to the console with their own accounts. Your backend calls the API with API keys. Both reach the same /v1
API, but some team-management actions accept only a signed-in person.
Signing in to the console
The console has no passwords. People sign in with Google or GitHub, using an account whose email address the provider has verified. Sign-in works only for addresses that an owner has added to the team; anyone else is turned away with a message to ask an owner. The first time someone signs in, their Google or GitHub account is bound to their membership, and after that Temper recognizes the account rather than the email.
A console session ends after 12 hours without use, 7 days after sign-in at the latest, when the person signs out, or as soon as they are removed from the team. Session tokens stay on the console's server; the browser only holds an HttpOnly cookie, and API keys never reach the browser.
Several teams
One account can be a member of several developers, for example an agency working for two clients. After signing in, the person picks a team. Each session is bound to one team, and switching teams (from the console's top bar) starts a new session for the other team.
Roles
Every member has one of two roles. Each team always has at least one owner.
| Role | Can do |
|---|---|
member | Day-to-day work: environments, approvals, policies, credentials, audit, usage and limits. Can list members, list API keys and view the webhook settings. |
owner | Everything a member can, plus managing members, API keys and the webhook. |
Owner-only actions
| Action | Needs a recent sign-in |
|---|---|
| Add a member | No |
| Change a member's role | No |
| Remove a member | Yes |
| Create an API key | Yes |
| Revoke another API key | Yes |
| Set the webhook URL or rotate its secret | Yes |
A recent sign-in means the session signed in within the last 10 minutes. Otherwise these calls fail with 403 reauth_required, and the
console asks the person to sign in again. A member who tries an owner-only action gets 403 forbidden.
To add someone, an owner enters their email address and role; they then sign in with the Google or GitHub account for that address.
Adding an existing member returns member_exists. You cannot remove the last owner or change their role to member (409 last_owner).
Removing a member signs them out of the console right away.
API keys
API keys (temper_sk_...) are for your backend. A key acts for the whole team, not for a person.
- Shown once. The full key appears only in the response that creates it. Temper stores only a hash, so a lost key cannot be
recovered; create a new one. Listings show the key's
name, a shortprefixto recognize it,created_at,created_by(the member who created it),last_used_atandrevoked_at. - Revocation is immediate. Revoking is idempotent; revoking a revoked key returns it unchanged. Keys have no expiry and no scopes, so revoke keys you no longer use.
- A key can revoke itself. If a key leaks, the backend holding it can switch it off at once without waiting for an owner. Revoking any other key needs an owner's recent console sign-in.
- Keys cannot manage the team. With an API key, adding, changing or removing members, creating keys and setting the webhook fail
with
403 session_required. A leaked key cannot be used to add a person or mint a fresh key for itself.
With a key you can still read team information: who am I, list members, list API keys and view the webhook settings.
Who am I
GET /v1/me returns the current team (developer, with id and name), the member (null when calling with
an API key) and auth, which is session or api_key. For a console session it also lists every team the account can switch to
(developers, each with id, name and role).
This example checks which team a key belongs to, then revokes that same key, as you might do in an incident:
import { Temper } from "@temper-hq/sdk";
const apiKey = process.env.TEMPER_API_KEY!;
const temper = new Temper({ apiKey });
const me = await temper.team.me();
console.log(me.developer.name, me.auth); // "api_key"
// Find this key by its prefix, then revoke it.
const keys = await temper.team.listApiKeys();
const mine = keys.filter((k) => k.revoked_at === null && apiKey.startsWith(k.prefix));
if (mine.length === 1) {
const revoked = await temper.team.revokeApiKey(mine[0].id);
console.log("revoked at", revoked.revoked_at);
}import os
from temper_hq import Temper
api_key = os.environ["TEMPER_API_KEY"]
temper = Temper(api_key=api_key)
me = temper.team.me()
print(me.developer_name, me.auth) # "api_key"
# Find this key by its prefix, then revoke it.
mine = [k for k in temper.team.list_api_keys() if k.revoked_at is None and api_key.startswith(k.prefix)]
if len(mine) == 1:
revoked = temper.team.revoke_api_key(mine[0].id)
print("revoked at", revoked.revoked_at)apiKey := os.Getenv("TEMPER_API_KEY")
client, err := temper.New(temper.WithAPIKey(apiKey))
if err != nil {
log.Fatal(err)
}
me, err := client.Team.Me(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Println(me.Developer.Name, me.Auth) // "api_key"
// Find this key by its prefix, then revoke it.
keys, err := client.Team.ListAPIKeys(ctx)
if err != nil {
log.Fatal(err)
}
var mine []temper.APIKey
for _, k := range keys {
if k.RevokedAt == nil && strings.HasPrefix(apiKey, k.Prefix) {
mine = append(mine, k)
}
}
if len(mine) == 1 {
revoked, err := client.Team.RevokeAPIKey(ctx, mine[0].ID)
if err != nil {
log.Fatal(err)
}
fmt.Println("revoked at", revoked.RevokedAt)
}The SDKs also have methods for the owner-only calls (team.addMember, team.createApiKey, team.setWebhook and so on). They need a
console session token rather than an API key, so in practice you use them through the console.
Related
- Team API reference
- Approval webhooks, including webhook signing secrets
- Security model