skip to content

Signing Keys & Issuance

What a service decides at signing time: where the private key lives, which component may mint, and how long a frozen fact stays safe to trust. Interviewers probe rotating a key without a flag day.

on this pageshow

questions

3

Where should a token issuer's private signing key live, and which component is allowed to mint with it?

level: middleimportance: must knowfreq 58%

answer

  1. one place, one owner
  2. who can physically reach the key
  3. process memory, hardware module, signing service
  4. a second minter forks the schedule

basics

~20 s

The private signing key should rest in the smallest place that can still mint — ideally a hardware module or a signing service that returns tokens and never the key — and exactly one component should be permitted to use it.

solid answer

~50 s

Treat minting as a privileged operation with a single owner. The key has three plausible homes: the minting process's own memory, which is fast and adds nothing to operate but puts the key in every heap dump and core file of that service; a hardware security module, which cannot export the key and counts every signature, at the price of latency and an availability dependency; or a signing service that holds the key and returns only signed tokens, which keeps one small blast radius and gives you a record of every mint, at the price of a network hop and a tier-one service of your own. The second decision matters more: exactly one component may mint. The moment a batch job or a test harness starts minting too, your rollover schedule, your audit trail and your claim vocabulary all have two owners.

code

pseudocode · 15 lines
pseudocode
# The signing service is the only process that can reach the private key.
# It returns signed tokens. It has no route that returns the key.

handle POST /sign(claims):
    caller = identify(request)          # machine credential or mutual TLS

    if caller is NONE:
        return 401 with WWW-Authenticate   # we do not know who is calling

    if caller not in ALLOWED_MINTERS:
        return 403                         # we know, and this one may not mint

    token = sign(claims, current_signing_key)
    audit(caller, claims.sub, key_label(current_signing_key))
    return token

go deeper

for a junior

Know that only the private key can mint tokens and the public half only checks them, and that the private key belongs in as few places as possible — never in source control, never handed to whichever service finds it convenient.

for a middle

Explain the three homes and what each trades: in-process speed against exposure in memory dumps, a hardware module's non-exportable key against latency and an availability dependency, a signing service's audit trail against a network hop on the issuance path.

for a senior

Show that you police the minting boundary as a reachability control, and that you know how the second minter actually arrives — a batch job at 02:00, a test harness — and what it costs you at the next rollover.

for a principal

Own the trade across the estate: the mint rate and the availability budget decide which custody model is affordable, and the recovery plan for a non-exportable key is the rollover path, which must be funded and rehearsed rather than assumed.

A syndication hub mints a signed entitlement token that several hundred subscriber newsrooms present when they pull copy off the wire. Two decisions are taken before any token exists, and no specification takes either of them for you: **where the private signing key physically rests**, and **which component is permitted to use it**. Both belong to the people who operate the issuer, and the second is the one candidates have usually never been asked about — yet it decides whether a key rollover a year from now is a change you schedule or a negotiation you chair. ## Where the key rests | Home | What it buys | What it costs | | --- | --- | --- | | The minting process's own memory | No extra hop, no new dependency, nothing new to operate | The key is present in heap dumps, core files and crash reports of that service, and whoever can read that process can mint whatever they like | | A hardware security module | The key cannot be exported, and every signing operation is counted and attributable | Latency on every mint, an availability dependency, and a written answer for the day the module is unreachable | | A signing service that returns tokens, never the key | One small blast radius, authenticated callers, a central record naming who minted what | A network hop on the issuance path, and a tier-one service of your own to run | The useful way to separate the three is to ask what a single compromise yields: - **In process** — read that memory once and you can mint valid tokens for as long as the key is trusted, anywhere, and nothing anywhere records that you did. - **Hardware module** — an attacker who reaches the calling process can still make the module sign, but only while they hold that access, and the module's own counters show the extra signatures afterwards. - **Signing service** — the same bound, plus an audit row per mint naming the caller, which is what turns "something minted an odd token at 02:00" from a theory into a query you can run. None of the three is right everywhere. A hub minting a few tokens a minute for a paid feed can easily afford a hardware module. A service minting thousands a second on a sign-in path may not, and either builds the signing service or accepts an in-process key with hard limits on who can attach to that process. ## The minting boundary The second decision is which component may mint at all, and the drift is always in one direction: **towards two**. An overnight batch job needs a token and it is quicker to hand it the key than to give it its own caller identity. A test harness mints its own. An internal support tool signs "just this once". Each is a small local convenience and a permanent structural change, because from then on: 1. **Rollover has two schedules.** The overlap window is bounded by whichever minter moves last, and somebody now has to chase that team. 2. **The audit trail is incomplete.** "Which tokens did we issue?" has two answers and only one of them is queryable. 3. **The claim vocabulary forks.** The second minter puts a slightly different shape into the token, and some verifier quietly starts accepting both shapes. 4. **Lifetime policy forks.** The `exp` you chose is enforced in one place and ignored in the other. Enforce the boundary with reachability rather than with convention. If the key lives behind a signing service, the boundary is that service's caller allowlist. If it lives in a hardware module, it is the module's access policy. If it lives in process memory, the boundary is that only one deployment carries the secret at all — which is precisely why the in-process option is the hardest of the three to hold for years. ## Generation, recovery and the half you hand out - **Generate the key where it will live.** A key generated on a workstation and copied into place has already existed somewhere you do not control, and you cannot un-know that. - **Decide the recovery story before you need it.** A key that genuinely cannot be exported also cannot be backed up, so your plan for a dead module is *rotate*, not *restore* — and that only works if the rollover path has been exercised at least once on a calm afternoon. - **Keep the public half separate in your head.** The verification key is not a secret; getting it to several hundred consumers is a different problem with entirely different failure modes. ## Where this decision stops Which signature algorithm the hub uses, how a published key-set document is laid out, and how a verifier selects the right key from one are specified elsewhere and are the same whatever you decide here. Custody and the minting boundary survive every one of those choices: you can change algorithm without changing who may mint, and no document format repairs a second minter.

  • A nightly batch job needs entitlement tokens. How do you give it one without giving it the key?
    Give the job its own machine identity and let it call the signing service like any other caller, with an allowlist entry and its own audit rows. If the key sits in a hardware module instead, the job calls the one minting component rather than the module. The point is that the number of processes holding the key stays at one, however many processes need tokens.
  • If the key cannot be exported from a hardware module, how do you survive losing the module?
    You do not restore it — you rotate to a key generated in a replacement module. That means the rollover path is your disaster plan, so it has to be exercised deliberately rather than discovered under pressure, and a second module holding a second key already published to verifiers turns the loss into a cutover instead of an outage.
  • What should the issuer log at mint time, and what must it never log?
    Log the calling component, the subject the token was minted for, which signing key was used, the lifetime granted, and a correlation identifier. Never log the token itself or the key material: a log line carrying a live token is a credential sitting in a system designed to be widely readable and long retained.

saying these in an interview costs you the question

  • The key is fine in an environment variable; only the code can read it.
  • Any service that needs a token can just sign one itself.
  • A hardware module makes key theft impossible, so nothing else matters.
  • Minting and verifying are the same job, so both need the private key.
  • We keep a copy of the private key in the deployment repository for recovery.
  • Signing is cheap, so where the key lives is a performance question.
open as a page

Your hub ships verification keys in each consumer's configuration file — how do you rotate the signing key without a flag day?

level: seniorimportance: should knowfreq 42%

basics

~20 s

Ship consumers a version that accepts two verification keys, confirm by measurement that they are running it, only then start signing with the new key, and withdraw the old one after the last token it signed has expired.

open as a page

Which facts are safe to freeze into a short-lived access token at mint, and which must be looked up per request?

level: principalimportance: should knowfreq 46%

basics

~20 s

Freeze facts that change rarely and are cheap to be wrong about for one token lifetime; look up per request any fact whose being wrong is expensive or irreversible. The token lifetime is the staleness budget, and someone must sign off that number.

open as a page