api_key_cruder

package
v1.23.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 4, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Overview

Package api_key_cruder reads and writes the keys an account registers, and records what they mint with.

The account's own queries carry `account = $n` with the argument taken from the session token: listing, registering and revoking are things an account does to its own keys, and there is no query here that can be asked about another's.

Minting is not one of those. It arrives with no session at all -- the assertion is the whole credential -- so its queries are keyed by the key's own id, and what they answer with is what the endpoint then checks: whether the key is revoked, whether it has expired, and whose account it belongs to.

Index

Constants

View Source
const AssertionRetention = assertion.Lifetime + 2*assertion.Leeway

* AssertionRetention is how long a spent assertion's identifier is kept, counted from when it * arrived. * * From the server's clock rather than from the "exp" the assertion carried, which is the only way * the record is certain to outlive the assertion: a client's "exp" decides whether an assertion is * still presentable, and an assertion accepted at the near edge of Leeway carries one that has * already passed. Stored under that, the row would be swept by the very statement below that tidies * up after it, and the assertion could be presented again for as long as it remained acceptable. * * The "exp" of an assertion arriving now may sit as far out as Lifetime and Leeway together, and the * assertion stays acceptable for a further Leeway past it -- hence Leeway twice. * * Derived from the window rather than written down, so that lengthening how long an assertion may * be presented for cannot quietly leave it remembered for less.

View Source
const AuthenticationLifetime = 30 * 24 * time.Hour

* AuthenticationLifetime is how long the sign-in row a key mints under is kept alive, extended at * every mint. * * It is not the token's lifetime, which is minutes. The row stands for "this key is in use", so * that a client minting every quarter of an hour appears in the account's activity as one entry * rather than as ninety-six a day -- with the list capped at fifty, the second shape would push * every browser sign-in off the end within a day, which is the opposite of what the page is for. * * A generous window is not a widening: what a mint is allowed to do is decided by the key's * revocation and expiry, both checked at every mint, and the token it produces is short regardless.

Variables

View Source
var ErrAssertionAlreadyUsed = errors.New("the assertion has already been used")

ErrAssertionAlreadyUsed says an assertion has been presented before: the identifier it carries is already stored against its key, which is what a replay looks like from here.

View Source
var ErrKeyRevoked = errors.New("the key has been revoked")

ErrKeyRevoked says the key was revoked by the time its mint was recorded, after the caller read it.

Functions

This section is empty.

Types

type Cruder

type Cruder struct {
	Database *sql.DB
}

func (*Cruder) Create

func (c *Cruder) Create(
	ctx context.Context,
	accountId string,
	key *public_key.Key,
	name string,
	expiresAt *time.Time,
) (*apiKeyTypes.ApiKey, error)

Create registers a key to an account.

The thumbprint is the primary key, so registering a key that is already registered -- to this account or to any other, revoked or not -- is a unique violation rather than a second row.

func (*Cruder) ReadBulkForAccount

func (c *Cruder) ReadBulkForAccount(ctx context.Context, accountId string) ([]*apiKeyTypes.ApiKey, error)

ReadBulkForAccount lists an account's keys, newest first, revoked ones included: a key that was revoked is part of what the account should see of its own history.

func (*Cruder) RecordMint

func (c *Cruder) RecordMint(
	ctx context.Context,
	key *Key,
	jti string,
	metadata *authenticationPkg.ClientMetadata,
) (*authenticationPkg.Authentication, error)

* RecordMint remembers the assertion, keeps the key's sign-in alive, and returns that sign-in with * the account it belongs to, ready for a token to be minted from. * * One transaction, and the order matters. The key's row is locked first and its revocation read * again: the caller read the key before verifying the assertion, and a revoke committed since must * not be followed by a sign-in made for the key it revoked, while one arriving after waits for this * transaction and ends the sign-in it leaves. The assertion is stored next, so that a replay fails * before anything else is touched; the sign-in is then reused where there is a live one for this * key, and made where there is not, which is what keeps one key to one entry in the account's * activity however often it mints. * * How long the assertion is remembered for is counted here, by the database's own clock, and both * statements below read it within the one transaction -- so the row that was just written cannot be * swept by the sweep that follows it, whatever a client's clock or a client's "exp" had to say.

func (*Cruder) RevokeForAccount

func (c *Cruder) RevokeForAccount(ctx context.Context, accountId string, keyId string) error

* RevokeForAccount takes a key out of use and ends what it minted, in one transaction. * * Both halves, because either alone leaves the account half revoked: the key with its sign-ins * still live would let the tokens already minted go on being renewed, and the sign-ins ended with * the key still registered would let the next mint make new ones. * * A key that is not this account's, one that does not exist, and one already revoked are all * sql.ErrNoRows, so the caller cannot learn from here that somebody else's key id is real.

func (*Cruder) SelectForMint

func (c *Cruder) SelectForMint(ctx context.Context, keyId string) (*Key, error)

SelectForMint reads a key by its own id, which is all a mint request names.

Nothing is decided here: a revoked or expired key comes back as it is, and the endpoint answers for it. What the caller must not do is read the account before verifying the signature.

type Key

type Key struct {
	Id        string
	Name      string
	Algorithm string
	PublicKey []byte
	AccountId string

	ExpiresAt *time.Time
	RevokedAt *time.Time
}

Key is a registered key as the mint path needs it: enough to verify a signature and to decide whether the key may still be used at all.

func (*Key) Expired

func (k *Key) Expired(now time.Time) bool

Expired says the key has passed the date it was registered with, if it was given one.

func (*Key) Revoked

func (k *Key) Revoked() bool

Revoked says the key has been taken out of use, whatever else is true of it.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL