KemalIdentity::Federation::LinkRepository
Storage for Links, shared by every federation protocol.
Small and boring on purpose. The security in federated login is in the flow — state,
nonce, PKCE, the assertion's iss and aud — and by the time anything reaches here the
provider's assertion has already been verified. What this layer has to get right is the
uniqueness constraint, which is doing more work than it looks like.
One repository for all protocols, and the reason is #for_account
A second protocol added later must write here rather than to a table of its own. Not because of the uniqueness constraint — that holds inside any one table, and two protocols naturally produce different issuers, so splitting them would not violate it. The reason is the two methods that ask a question about an account rather than about a link:
#for_accountis "which providers is this account linked to". Answered from half the rows, it is a management screen that lies.#unlinkis guarded by the application against removing somebody's last way in. That check reads#for_account, so against a split store it can strand an account with no login method left — which is the one outcome unlinking must never produce.
Both break silently and both break in the direction of losing access, which is why this is a
Federation type and not an OIDC one (blueprints/0024-federation-namespace.md).
Instance methods
The account (issuer, subject) belongs to, or nil.
The hot path of a federated login, and the only lookup that may decide who somebody is.
Every external identity attached to an account, for a management screen. Oldest first.
Records that (issuer, subject) is this account.
Raises InfrastructureError when that pair is already linked — including to the same
account. Silently accepting a second link is how one provider account ends up attached
to two local ones, and then whichever row is found first decides who somebody logs in as.
The application checks with #find and decides; this refuses to guess.
Records that this link was just used to authenticate. Returns false for an unknown pair.
Removes one link. Returns false if it was not there.
An application that offers this must make sure the account keeps some way in — removing the only link from an account with no password is how somebody is locked out permanently. That check belongs in the application, which is the only thing that knows what else the account has.