@persona-claims/gatekeeper
v0.2.0
Published
Transport-agnostic gatekeeper logic.
Readme
@persona-claims/gatekeeper
Transport-agnostic gatekeeper logic.
A gatekeeper (псевдоним in persona.claims terms) is a privacy intermediary. It takes a unique Claim — typically a government-issued personal identifier such as person.snils — and produces a new claim carrying only a verifier-scoped pseudonym derived from that identifier. Different verifiers see different pseudonyms for the same person, so they cannot cross-correlate users, while still being able to recognise the same person on repeat visits.
The classic use case from the landing page: a service needs to ensure "одна учётка на одного человека" (one account per person) without ever seeing the underlying identifier.
The pseudonym is HMAC-SHA256(secret, stableJson(uniqueValue) + "||" + verifierPublicKey).
What It Owns
- gatekeeper signing key bootstrap
- HMAC secret material
- incoming claim validation (issuer DNS + signature)
- HMAC-based scoped pseudonym derivation
- issuance of
gatekeeper.pseudonymclaims - gatekeeper-side revocation list (so the unique claim cannot be re-pseudonymised endlessly)
Issuing a Pseudonym
import { Gatekeeper } from "@persona-claims/gatekeeper";
const gatekeeper = await Gatekeeper.create({
id: "gatekeeper.example",
publicUrl: "https://gatekeeper.example",
secret: process.env.GATEKEEPER_SECRET, // stable HMAC secret
});
// `uniqueClaim` is a verified claim like `person.snils` produced by a
// trusted issuer. `verifierPublicKey` is the verifier this pseudonym
// will be presented to.
const { claim, pseudonym } = await gatekeeper.issue({
claim: uniqueClaim,
verifierPublicKey,
});
// `claim.iss === "gatekeeper.example"`, `payload.typ === "gatekeeper.pseudonym"`,
// `payload.dat === { pseudonym }`. The verifier sees the pseudonym and nothing else.The same uniqueClaim + verifierPublicKey always produce the same pseudonym (because HMAC is deterministic). The same uniqueClaim with a different verifier produces a different pseudonym — that's the whole point.
Deriving Without Issuing
const id = gatekeeper.derive(uniqueValue, verifierPublicKey);
// returns the HMAC hex digest; useful for lookups before/around issuance.Low-Level API
newSession(config)derive(secret, uniqueValue, verifierPublicKey)→ hex pseudonymissue(session, params)→{ claim: Claim, pseudonym: string }revoke(session, uid)/isRevoked(session, uid)
Class API
Gatekeeper.create(config)gatekeeper.derive(uniqueValue, verifierPublicKey)gatekeeper.issue(params)gatekeeper.revoke(uid)/gatekeeper.isRevoked(uid)gatekeeper.key,gatekeeper.id,gatekeeper.publicUrl
Boundaries
- No REST transport, no request parsing, no server framework
- For the reference REST transport, see apps/gatekeeper
