GoodMemGoodMem
How-To GuidesUsers and Access

Redeem an Enrollment

Exchange a one-time enrollment credential for your first GoodMem API key.

Redeem an Enrollment

An administrator has created a GoodMem account for you and sent you an enrollment credential — a one-time secret that starts with gme_. This guide turns that credential into your own API key: a key that belongs to you, authenticates as you, carries whatever authority your account has, and does not expire. The administrator's side of this exchange is covered in Onboard a User.

The enrollment credential is good for exactly one key, and it expires 24 hours after it was created. If yours has expired, ask your administrator for a new one.

Before You Start

  • The enrollment credential from your administrator.
  • Your server's address: the gRPC address for the CLI (for example https://goodmem.example.com:9090), or the REST base URL for cURL and HTTPie (for example https://goodmem.example.com:8080, or your GoodMem Cloud instance's https:// hostname).
  • No API key. Enrollment is designed to work without one.
export GOODMEM_REST_URL="https://goodmem.example.com:8080"
export GOODMEM_ENROLLMENT_TOKEN="gme_..."

GoodMem Cloud instances do not expose the gRPC port the CLI uses. On Cloud, redeem over REST with the cURL or HTTPie tab, or open /console/enroll on your instance and paste the credential there. If your own server uses a self-signed certificate, add -k to curl and --verify=no to HTTPie.

1. Supply the Credential

goodmem user enroll accepts the credential from exactly one of four sources:

SourceInvocation
Hidden promptgoodmem user enroll --token-prompt
Owner-only filegoodmem user enroll --token-file ./enrollment-token
Environment variableGOODMEM_ENROLLMENT_TOKEN='gme_...' goodmem user enroll
Literal flag or stdingoodmem user enroll --token 'gme_...' or --token - with piped input

Run interactively with no source at all and the CLI falls back to the hidden prompt, which is the sensible default for a human at a terminal. Supplying more than one source is an error. Passing the credential with --token works, and the CLI will remind you that it just landed in your shell history and in the process listing of anyone who ran ps at the right moment.

Over REST there is one source: the enrollmentToken field of the request body. Keep it out of your shell history the same way — read it from an environment variable or a file rather than typing it into the command line.

2. Run the Enrollment

The exchange is a single call to the completion endpoint. It is the only authorization-related endpoint that takes no x-api-key header; the enrollment credential is the authentication.

goodmem user enroll --token-prompt
curl -sS --json @- "$GOODMEM_REST_URL/v1/user-enrollments:complete" <<JSON
{ "enrollmentToken": "$GOODMEM_ENROLLMENT_TOKEN" }
JSON
http POST "$GOODMEM_REST_URL/v1/user-enrollments:complete" \
  enrollmentToken="$GOODMEM_ENROLLMENT_TOKEN"

A successful run looks like this on the CLI; the REST response carries the same facts as apiKey (metadata), rawApiKey, and alreadyCompleted:

Enrollment Completed: true
API Key ID:          0198c0f2-4d31-7a8e-9b1c-3f6d82a90e44
Key Prefix:          gm_mzxw
Raw API Key:         gm_mzxw6ytboiww6z3foj2xezltoq

The raw API key is shown once. Store it in your secret manager or password vault before doing anything else.

Who Generates the Key

By default the CLI generates the key material itself, locally, before it talks to the server. It saves the exact key it generated in an owner-only recovery file under ~/.goodmem/enrollment-recovery/, submits it along with your credential, prints the key after the server confirms, and then deletes the recovery file.

The reason for this choreography: this is your first credential. If the exchange fails partway — a dropped connection, a timeout — you have no other key with which to ask the server what happened. Because the CLI retained the exact key it proposed, rerunning the same command is safe: the server either completes the enrollment or recognizes the retry and confirms the key it already stored. Either way you end up with a working key instead of a burned credential.

The plain REST call above is server-generated mode, the same as goodmem user enroll --token-prompt --server-generate-key: the server mints the key and returns it once. It is the simpler contract, and some environments prefer key material that never touched a client's random-number generator.

In server-generated mode, a response lost after the server commits is unrecoverable. The enrollment is consumed, the key exists, and nobody can display it — the server stores only a verifier. An administrator has to revoke the stranded key and start the enrollment over. Client-generated mode does not have this failure case.

To get the CLI's retry-safe behavior over REST, generate the key material yourself and send it with the credential. A canonical key is gm_ followed by 26 unpadded lower-case Base32 characters encoding 16 random bytes; the ID is any UUID. Keep both until the server has confirmed, then retry the identical request as often as needed — a retry after a lost response returns the stored result with alreadyCompleted: true:

export MY_API_KEY_ID="$(uuidgen | tr 'A-Z' 'a-z')"
export MY_RAW_API_KEY="gm_$(head -c 16 /dev/urandom | base32 | tr -d '=' | tr 'A-Z' 'a-z')"

curl -sS --json @- "$GOODMEM_REST_URL/v1/user-enrollments:complete" <<JSON
{
  "enrollmentToken": "$GOODMEM_ENROLLMENT_TOKEN",
  "apiKeyId": "$MY_API_KEY_ID",
  "rawApiKey": "$MY_RAW_API_KEY"
}
JSON
export MY_API_KEY_ID="$(uuidgen | tr 'A-Z' 'a-z')"
export MY_RAW_API_KEY="gm_$(head -c 16 /dev/urandom | base32 | tr -d '=' | tr 'A-Z' 'a-z')"

http POST "$GOODMEM_REST_URL/v1/user-enrollments:complete" \
  enrollmentToken="$GOODMEM_ENROLLMENT_TOKEN" \
  apiKeyId="$MY_API_KEY_ID" \
  rawApiKey="$MY_RAW_API_KEY"

The two key fields travel as a pair; sending one without the other is invalid. In this mode the response omits rawApiKey — you already hold it — and confirms the key's metadata in apiKey, with apiKey.apiKeyId equal to the ID you sent. Responses are marked Cache-Control: no-store.

If the Call Fails

  • On any transport or server error, the CLI keeps the recovery file and tells you where it is. Run the same command again. Over REST in client-generated mode, resend the identical request; in server-generated mode, ask your administrator to check whether the enrollment was consumed.
  • An expired, revoked, already-consumed, or simply wrong credential gets one generic rejection; the server does not distinguish the cases. Confirm the credential with your administrator, who can inspect its status and issue a replacement.
  • The completion endpoint is rate-limited per source address, returning HTTP 429 with a Retry-After header over REST. Wait a minute and retry — in client-generated mode the retry is safe.

3. Mint a Backup Key

Enrollment happens once per account. If this key is later lost with no other key in place, there is no re-enrollment and no administrator override. A sensible first move after storing the key is minting a second one as a backup, authenticating with the key you just received:

goodmem apikey create --label purpose=backup
curl -sS --json '{"labels": {"purpose": "backup"}}' "$GOODMEM_REST_URL/v1/apikeys" \
  --header "x-api-key: gm_..."
http POST "$GOODMEM_REST_URL/v1/apikeys" x-api-key:"gm_..." labels:='{"purpose": "backup"}'

4. Configure Your Tools

Point a CLI profile at your server with the new key:

goodmem profile create default --url https://goodmem.example.com:9090 --api-key gm_...

SDKs and direct REST calls use the same key in the x-api-key header, and the console takes it when you create a profile there.

If Your Key Cannot Do Anything

Enrollment produces a credential, and only a credential. Your authority comes from the roles and grants on your account, which your administrator assigns separately. If the administrator skipped that step, your new key authenticates successfully and is then denied almost everything — the key works; there is nothing it is allowed to do. The fix is on the administrator's side: assigning the standard USER role, described in Onboard a User. How keys relate to the authority behind them is covered in API Keys and Ceilings.