Service tokens from a script
A service token is a key that belongs to no person: the key of a build agent, a deployment host, a scheduled job. An administrator makes one on Admin → Tokens. This page is about doing the same from a script, so that giving a new host its own key, and taking it away again, needs nobody at a browser.
What it takes
A service token with the admin scope, sent like any other key: X-ApiKey, the password of Basic authentication,
or a Bearer token. A super administrator makes that one on the tokens page. Keep it where your automation keeps its
other secrets; it is the key that makes keys.
What that key can do over the API is deliberately less than what a person can do on the page:
- It makes, lists and revokes tokens that read, push and delete.
- It never makes a token with the admin scope, and never revokes one. A key that can make admin keys can make more of itself; that stays with a super administrator on the page.
- It does not see or revoke personal keys. Those belong to their owners.
Make a token
$admin = @{ 'X-ApiKey' = $adminKey }
$made = Invoke-RestMethod -Method Post "https://packages.example/api/management/tokens" -Headers $admin `
-ContentType 'application/json' -Body (@{
name = 'build-agent-07'
scopes = @('read', 'push')
feed = 'modules' # leave out for every feed
expiresInDays = 90 # leave out for a token that does not end
} | ConvertTo-Json)
$made.token # the secret. Shown in this answer and never again.
| Field | Meaning |
|---|---|
name |
What the token is called in lists and in the logs. Required. |
scopes |
One or more of read, push, delete. Pushing and deleting include reading. Required. |
feed |
A feed or an asset directory to limit the token to. Without it the token applies to all of them. |
expiresInDays |
1 to 3650. Without it the token does not end. |
The answer is 201 with the token: its id, name, prefix (the first characters, to recognise it by), scopes,
feed, expiresUtc and the secret in token. Store the secret straight away; FiGet keeps only its hash.
List and revoke
$tokens = Invoke-RestMethod "https://packages.example/api/management/tokens" -Headers $admin
$tokens | Where-Object { $_.active -and $_.daysLeft -le 14 } | Format-Table id, name, feed, daysLeft
Invoke-RestMethod -Method Delete "https://packages.example/api/management/tokens/$($made.id)" -Headers $admin
Each entry has active (not revoked and not ended), lastUsedUtc, and daysLeft for a token that ends: the whole
days it has left, rounded up. A revoked token is refused from the next request on. Revoking one that is already
revoked is not an error.
Replacing a key without a gap
Two tokens can be valid at the same time, so a replacement never needs a moment where neither works:
- Make the new token, with the same scopes and feed.
- Give it to whatever used the old one.
- Watch
lastUsedUtcof the old one stop moving, then revoke it.
Tokens that are about to end
A token with an expiry stops working without telling whoever uses it. FiGet says so ahead of time, twice: fourteen days and three days before the end.
- The tokens page marks the token: ends in 5 days.
- The audit log gets a
token.expiringentry, and the server's own log a warning, once at each distance. - The API's list counts down in
daysLeft, for a job of your own that replaces keys before they end.
The check runs once a day (FiGet:Jobs:TokenExpiryWatch). It covers personal keys as well as service tokens.
What is refused, and how
| Answer | When |
|---|---|
401 |
No key was sent, or what was sent as a Basic password or Bearer token is not a valid key. |
403 |
A key sent as X-ApiKey that is not valid; a valid key that is not a service token with the admin scope; a request that asks for the admin scope; revoking a token that has it. |
400 |
The body is not what the table above describes. The error field says which part. |
404 |
Revoking an id that is not a service token. |
Making and revoking a token are in the audit log as token.create and token.revoke, by the name of the key that
did it.