Skip to main content

Auth API

Table of Contents​

Top

upsquad/auth/v1/api_key.proto​

APIKeyInfo​

APIKeyInfo is the non-secret metadata for a single API key.

FieldTypeLabelDescription
key_idstringkey_id is the UUID of the key row.
key_prefixstringkey_prefix is the first 12 characters for human identification.
member_idstringmember_id is the member the key was issued to.
team_idstringteam_id is the team the key belongs to.
scoped_agent_idstringoptionalscoped_agent_id is set if the key is restricted to a single agent.
is_activeboolis_active indicates whether the key is currently valid.
created_atgoogle.protobuf.Timestampcreated_at is when the key was created.
expires_atgoogle.protobuf.Timestampoptionalexpires_at is when the key expires, if set.

CreateAPIKeyRequest​

CreateAPIKeyRequest provisions a new API key.

The key's IDENTITY is never taken from this message (#3379): the org, the member and the clearance come from the verified caller. The one identity- adjacent thing a client may choose is unit_id, and only because the server checks it against the caller's own memberships (#3416).

FieldTypeLabelDescription
team_idstringDeprecated. team_id is parsed and IGNORED since #3379 — a minted key binds the verified caller's own identity, never a value the wire asserts. Use unit_id to say which of the caller's units the key is scoped to.
member_idstringDeprecated. member_id is parsed and IGNORED since #3379, for the same reason.
scoped_agent_idstringoptionalscoped_agent_id optionally restricts the key to a single agent.
expires_atgoogle.protobuf.Timestampoptionalexpires_at optionally sets key expiration.
unit_idstringunit_id is the org unit (unit_type = 'team') the key is scoped to, and it is REQUIRED (#3416).

It is a REQUEST, not an assertion: the server refuses the mint unless the verified caller holds an active membership of that unit in their own org, so the wire may only SELECT AMONG THE CALLER'S OWN AUTHORITIES — the same construction as scoped_agent_id, which can only narrow.

It is required rather than derived because org_unit_memberships is many-to-many: a member in two units has no single "their unit", and choosing one server-side would make an arbitrary tie-break into an authorisation input. A key with no unit cannot complete a Model Gateway call at all — gate 5/binding refuses it with binding_unit_unresolved — so minting one would be minting a dud.

One key = one unit. A member of two units mints two keys. |

CreateAPIKeyResponse​

CreateAPIKeyResponse returns the newly created key details.

FieldTypeLabelDescription
key_idstringkey_id is the UUID of the created key row.
raw_keystringraw_key is the full plaintext key. Only returned once, on creation.
key_prefixstringkey_prefix is the first 12 characters for human identification.
created_atgoogle.protobuf.Timestampcreated_at is when the key was created.
expires_atgoogle.protobuf.Timestampoptionalexpires_at is when the key expires, if set.

ListAPIKeysRequest​

ListAPIKeysRequest lists keys in the caller's organisation.

FieldTypeLabelDescription
member_idstringoptionalmember_id optionally filters by member. Empty returns all org keys.

ListAPIKeysResponse​

ListAPIKeysResponse returns key metadata.

FieldTypeLabelDescription
keysAPIKeyInforepeatedkeys is the list of API key metadata records.

RevokeAPIKeyRequest​

RevokeAPIKeyRequest revokes a key by ID.

FieldTypeLabelDescription
key_idstringkey_id is the UUID of the key to revoke.

RevokeAPIKeyResponse​

RevokeAPIKeyResponse is empty on success.

RotateAPIKeyRequest​

RotateAPIKeyRequest rotates an existing key by ID.

FieldTypeLabelDescription
key_idstringkey_id is the UUID of the key to rotate.

RotateAPIKeyResponse​

RotateAPIKeyResponse returns the new key and confirms revocation of the old.

FieldTypeLabelDescription
new_key_idstringnew_key_id is the UUID of the newly created key.
raw_keystringraw_key is the new full plaintext key. Only returned once.
key_prefixstringkey_prefix is the first 12 characters of the new key.
revoked_key_idstringrevoked_key_id is the UUID of the old key that was revoked.

APIKeyService​

APIKeyService manages the lifecycle of member API keys within an organisation. All operations are scoped to the caller's org_id via JWT-derived claims.

Method NameRequest TypeResponse TypeDescription
CreateAPIKeyCreateAPIKeyRequestCreateAPIKeyResponseCreateAPIKey provisions a new API key for a member. The raw key is returned only once in the response and is never stored or retrievable.
RotateAPIKeyRotateAPIKeyRequestRotateAPIKeyResponseRotateAPIKey atomically revokes an existing key and creates a replacement. The new raw key is returned only once.
RevokeAPIKeyRevokeAPIKeyRequestRevokeAPIKeyResponseRevokeAPIKey deactivates an existing key. The key row is retained for audit purposes but is no longer valid for authentication.
ListAPIKeysListAPIKeysRequestListAPIKeysResponseListAPIKeys returns metadata for all keys in the caller's organisation, optionally filtered by member_id.

Top

upsquad/auth/v1/context.proto​

TenantContext​

TenantContext is the authenticated caller envelope constructed by the gateway after JWT verification. It flows through middleware and is attached to request contexts so downstream handlers, interceptors, and RLS-aware DB helpers share a single source of truth for the caller's tenant, identity, clearance tier, and global role grants.

FieldTypeLabelDescription
tenant_idstringTenant (organisation) id the caller is authenticated against.
member_idstringMember id of the caller within tenant_id. May be empty when the Clerk subject has not yet been mapped to a members row (e.g. first request post-signup before the provisioning webhook has fired) — consumers MUST treat an empty value as "no scoped grants known".
clearance_levelint32Numeric clearance tier in the closed range [1, 5]. Mirrors members.clearance. Zero is legal and means "not yet resolved"; governance gates default-deny on zero.
clearance_labelstringDisplay-grade clearance label. One of: 1 => "Standard" 2 => "Internal" 3 => "Sensitive" 4 => "Privileged" 5 => "Executive" Matches the CHECK constraint on members.clearance_label added in migration 062. Empty string when clearance_level == 0.
global_role_idsstringrepeatedGlobal role ids granted to member_id (scope_type='global' rows in role_assignments, deleted_at IS NULL). Sorted for deterministic serialisation. Length is strictly <= 20 per HLD §6.2.3; the builder REJECTS construction for members that exceed the cap so this field is safe to trust as bounded at the boundary.

Scoped role ids (org_unit / member) are intentionally OMITTED here and resolved via PermissionResolver. See the package documentation on internal/rbac/resolver.go for the rationale (HLD §5.3 / §4.3.2). | | clerk_user_id | string | | Clerk user id (Clerk's sub claim). Preserved so downstream audit writers can attribute actions even when member_id is empty. |

Scalar Value Types​

.proto TypeNotesC++JavaPythonGoC#PHPRuby
doubledoubledoublefloatfloat64doublefloatFloat
floatfloatfloatfloatfloat32floatfloatFloat
int32Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead.int32intintint32intintegerBignum or Fixnum (as required)
int64Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead.int64longint/longint64longinteger/stringBignum
uint32Uses variable-length encoding.uint32intint/longuint32uintintegerBignum or Fixnum (as required)
uint64Uses variable-length encoding.uint64longint/longuint64ulonginteger/stringBignum or Fixnum (as required)
sint32Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s.int32intintint32intintegerBignum or Fixnum (as required)
sint64Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s.int64longint/longint64longinteger/stringBignum
fixed32Always four bytes. More efficient than uint32 if values are often greater than 2^28.uint32intintuint32uintintegerBignum or Fixnum (as required)
fixed64Always eight bytes. More efficient than uint64 if values are often greater than 2^56.uint64longint/longuint64ulonginteger/stringBignum
sfixed32Always four bytes.int32intintint32intintegerBignum or Fixnum (as required)
sfixed64Always eight bytes.int64longint/longint64longinteger/stringBignum
boolboolbooleanbooleanboolboolbooleanTrueClass/FalseClass
stringA string must always contain UTF-8 encoded or 7-bit ASCII text.stringStringstr/unicodestringstringstringString (UTF-8)
bytesMay contain any arbitrary sequence of bytes.stringByteStringstr[]byteByteStringstringString (ASCII-8BIT)