enum

KemalIdentity::AssuranceLevel

Inherits Enum < Comparable < Value < Object

How strongly the current principal was authenticated.

Deliberately not a boolean logged_in?: "typed a password just now", "typed a password two hours ago" and "restored silently from a remember-me cookie" are three different security situations that a boolean cannot tell apart. Combined with Principal#authenticated_at (how recently) this is what makes require_fresh!(within: 5.minutes) a caller decision rather than a configured global.

The numeric value is persisted in auth_sessions.assurance as a SMALLINT. Append only. Never renumber an existing member — a renumbering silently reclassifies every session row already on disk. The gaps of ten exist so an intermediate level can be added later without breaking the ordering that Comparable gives us.

Constants

Remembered = 10_i16

Restored from a remember-me cookie. The account holder has not typed a password recently and may not be present at all. Below Password on purpose.

ApiToken = 15_i16

A long-lived API token was presented — a personal access token, not a browser session.

Above Remembered because the holder deliberately created this credential and can revoke it, and below Password because no person typed anything: a token in a CI job's environment proves possession of a secret, not the presence of the account holder.

Principal#fresh? is therefore false for it, so require_fresh! refuses a token-bearing request outright. That is the intended answer. An automated client cannot re-authenticate interactively, so a destructive account action should not be reachable with a token in the first place.

Password = 20_i16

A password (or equivalent single factor) was verified in this session's lifetime.

Recovery = 25_i16

A single-use recovery code was spent in place of a second factor.

Above Password because a second thing was proved, and below MFA because of what that thing is: a printed or stored list, phishing-resistant in no sense, held by whoever found the piece of paper. A recovery code is how somebody gets back in after losing a device; it is not how the sharpest action in the application should become available.

So a permission declared minimum_assurance: MFA — "changing payout details needs phishing-resistant MFA" — is not satisfied by one, while everything at Password and below is. Before this level existed the documented flow raised a recovery redemption to MFA, and the strongest gate in the system was reachable through its weakest path with nothing in the principal saying so (blueprints/0025, MFA-04).

25 rather than 21: the gaps of ten are for exactly this, and the midpoint leaves room on both sides.

MFA = 30_i16

A second factor was verified in addition to the first.

Instance methods

api_token?

Returns true if this enum value equals ApiToken

Source
mfa?

Returns true if this enum value equals MFA

Source
password?

Returns true if this enum value equals Password

Source
recovery?

Returns true if this enum value equals Recovery

Source
remembered?

Returns true if this enum value equals Remembered

Source