Grant and revoke API keys¶
Nerthus.Core (until cutover). This page describes the frozen system that runs today and is deleted at cutover. Replaced by: not yet written.
A person signs in through Margonem or Discord. Code cannot. When someone's script, bot, or dashboard needs to act as them, a Radny grants them an API key - a long-lived key recorded in that person's entry in nerthus.contributors.md, at the root of the lore repository. This page shows when a key is the right answer, how to grant one, how to revoke one, and how to swap an old key for a new one without a gap.
When a key is the right answer¶
Grant a key when a person needs the tool to work for them while they are away from the keyboard - a script, a bot, a dashboard. Signing in works for a person; a key works for code. A sign-in lapses after a few hours, a key keeps working until you take it away. And a key is good on every town at once - every address the tool answers at - so it keeps working even when the tool moves between towns.
A key is exactly as powerful as its owner, at all times. It lets the code do what the person may do, nothing more. When the person's role changes, every key of theirs follows on its own - you never grant a new key to reflect a new role.
Keys are for the people listed in nerthus.contributors.md - the file where everybody in the campaign has a block, players and Rada alike. Each block sits under the ## Osoby heading:
## Osoby
### Stefan
- @margonemid: 100001
- @rola: narratorzy
- @discord: narrator-stefan, narratorzy
The heading is the person's nick. @margonemid is their Margonem profile id - the same id their sign-in uses. @rola names their function, and @discord is where the tool reaches them. If the person has no block yet, add one shaped like this first.
Grant a key¶
1. Ask the tool to mint¶
The command runs in a PowerShell session with the tool's module loaded - the same kind of session the repository was adopted from. Name the owner's Margonem id:
hash : eaf2b520e5412a1d6bb8636e69e487926bcea5c94af1980d628d15035386bea1
line : - @klucz_api: sha256:eaf2b520e5412a1d6bb8636e69e487926bcea5c94af1980d628d15035386bea1
margonemId : 100001
claimPath : /api-keys/claim/eaf2b520e5412a1d6bb8636e69e487926bcea5c94af1980d628d15035386bea1
The tool minted the key and is holding it for one pickup. Nothing here is the key itself: line is what you will paste into the file, and claimPath is where the owner picks the key up - once. You never see the key at all, and that is the point: only its owner does.
You may only mint for a person as powerful as yourself or weaker. Minting for someone whose permissions exceed your own is refused - a key is exactly as powerful as its owner, so handing a stronger person's key around would be handing around power you do not hold.
2. Hand the pickup link over¶
Send the owner the pickup address - the tool's address on any town followed by claimPath:
https://dev-torneg.nerthus.pl/v1/api/api-keys/claim/eaf2b520e5412a1d6bb8636e69e487926bcea5c94af1980d628d15035386bea1
The first visit hands out the key and destroys the pickup; a second visit finds nothing. That is your tamper-seal, too: if the owner opens the link and it is already empty, someone else got there first - delete the pasted line, mint again. A pickup left unvisited for an hour expires on its own; mint again if that happens.
3. Paste the printed line¶
Open nerthus.contributors.md and paste the Line value into the owner's block. Stefan's block after the paste:
## Osoby
### Stefan
- @margonemid: 100001
- @rola: narratorzy
- @klucz_api: sha256:eaf2b520e5412a1d6bb8636e69e487926bcea5c94af1980d628d15035386bea1
- @discord: narrator-stefan, narratorzy
The @klucz_api line holds the key's fingerprint, never the key. That is why committing it is safe. Paste only the printed line. If the key itself - the nak_ value - lands in the file, the tool refuses it and that key never works.
4. Commit¶
Commit the file. The commit is the grant going live. Every town picks the change up on its own, and the slowest of them is on a fifteen-minute schedule (measured 2026-08-28), so within about 15 minutes the key works everywhere. There is nothing to restart and nothing else to run. By the quarter hour, Stefan's session-reminder bot is at work on every town.
Keys answer only from the main line
Commit the grant to the repository's main line. A town that is - for whatever reason - serving some other line of work refuses every key until it is back on the main one.
Give a key a validity window¶
A key can carry the same (from:to) date range every other dated line in the lore repository uses - append it to the pasted line, or have the tool print it for you:
Either side may stay open: (:2027-01-31) works until the end of that day, (2026-08-01:) starts working that day and never stops, (2026-08-01:2027-01-31) does both. The key works through the whole of the last named day and stops on its own the day after - nothing to delete, nothing to remember. Write dates in that exact shape: 2027-01-31 is 31 January 2027. A line without a range lives until the line is deleted.
Revoke a key¶
Delete the @klucz_api line from the owner's block and commit. That is the whole of it - nothing else to clean up anywhere.
A deleted key can work for another quarter hour
Each town picks up the change on its own schedule, and the slowest is on fifteen minutes (measured 2026-08-28), so a deleted key can keep working for up to about 15 minutes on some towns. When the key you are revoking has leaked, count on those minutes - do not assume the delete lands everywhere at once.
Rotate a key¶
Rotation swaps an old key for a new one without a gap: add, wait, delete.
- Mint a new key for the same owner and paste its printed line under the old one. Two
@klucz_apilines in one block are fine - both keys work. - Hand the pickup link over, and wait until the owner's script runs on the new key.
- Delete the old line and commit.
A bot rotates itself the same way: a person with @rola: boty may mint a fresh key for their own id - and only their own - so the swap needs a Radny only for the paste and the commit.
Grant a key to a role¶
A key may belong to a whole role instead of a person - paste the printed line into the role's block under ## Role (mint it with New-NerthusApiKey -Rola boty). Whoever holds that key acts with the role's permissions, but as nobody in particular: nothing "own" works, and the audit trail says the role's name, not a person's. Use it for shared automation that outlives any one owner; prefer a personal key whenever one person answers for the code.
Stefan's block mid-rotation, both lines in place:
### Stefan
- @margonemid: 100001
- @rola: narratorzy
- @klucz_api: sha256:eaf2b520e5412a1d6bb8636e69e487926bcea5c94af1980d628d15035386bea1
- @klucz_api: sha256:60303ae22b998861bce3b28f33eec1be758a213c86c93c076dbe9f558c11c752
- @discord: narrator-stefan, narratorzy
At no point in the swap is Stefan's bot without a working key.
A named token is the other thing a Radny can mint¶
A named token is the second credential, and it is not a key. Nothing about it is written into nerthus.contributors.md, it belongs to nobody, and it is printed once and never again. Where a key stands for a person and inherits that person's permissions for as long as the line lives, a token stands for a job: you name the permissions on it yourself, and you may cap how long it works.
That prints the token's one and only copy - save it before you close the window. Get-NerthusToken lists what has been minted, names and expiry rather than values, and Remove-NerthusToken kills one by its id.
A token also works on one town only. Nothing commits it to the repository, so the other towns never learn it exists - the opposite of a key, which every town picks up within the quarter hour.
Reach for a token when the thing needing it is a job rather than a person: a one-off migration, a script somebody runs beside you for an afternoon, a machine that is nobody in the campaign. Reach for a key in every other case, and especially when one person answers for the code - a key follows its owner's role for the rest of its life, and a token follows nobody.
A token can be stronger than the person who minted it
Nothing checks a token's permissions against your own, and nothing on the token records who asked for it or why. Name every one after the job it does, give it only the permissions that job needs, cap it with -TtlSeconds, and revoke it the day the job ends rather than the day you remember it.
Related¶
- Start here - the roles, signing in, and what each role may do.
- People and roles - the same file, its
@rolalines and@discordchannels. - Use the web dashboard - the site a klucz API signs you in to.