KeyLockr supports two explicit third-party sign-in paths: new native/mobile integrations use Delegated SSO v1, while existing advanced direct clients retain the temporary-WebSocket and QR compatibility flow. Both approve only on the phone and neither hands out a reusable KeyLockr password; this page keeps the two paths separate.
The app never receives a reusable KeyLockr login password. After you approve on your phone, it receives a one-time result signed by the KeyLockr server and encrypted for that recipient.
Before it draws anything, your phone asks the server which registered service is behind the request and puts that name on screen. Nothing is written anywhere until you tap approve.
You grant one named capability at a time, each spelled out on the approval screen. One tap on the phone stops future access; it cannot claw back content the service already read or stored.
The source app calls its own backend /start, then opens KeyLockr Mobile with a signed deep link or QR. Mobile calls app_delegated_info and app_delegated_approve, returns an opaque result to the exactly registered return_url, and the source app submits it with its private finish_secret to its own backend /finish.
Prefer a verified-domain Universal Link/App Link. A native app may also register an exact canonical custom scheme, such as cing://sso/callback. The third-party app and backend do not call KeyLockr APIs and do not open a temporary WebSocket.
A direct client creates a handshake and temporary WebSocket, then shows a QR/deep link containing only the tmp_id. The Safe identifies the service with app_scan_info and approves with app_add. The server-signed app_auth_result can arrive through the WebSocket or native callback.
Delegated does not use /app_verify, a temporary WebSocket, or data_deferred, and never silently falls back to legacy after failure. The two interactive diagrams below keep the wire steps of each path separate.
This timeline begins at the third-party backend /start, crosses the signed deep link or QR, Mobile verification and approval, and the exactly registered return_url, then ends at the third-party backend /finish. The finish_secret exists only inside that backend trust boundary; it never enters the app, callback, or KeyLockr. Click any box or arrow for the full story; press Esc to close.
finish_secret and finishes the login.
This is the legacy timeline: left to right is handshake, approval on the phone, and server issuance, then back around to the finished session. Dashed lines are paths that exist afterwards, not steps in this run; this diagram does not describe delegated /start and /finish. Click any box or arrow for the full story; press Esc to close.
There are exactly three capabilities, named the same way in the code. The ceiling for each is fixed when the service registers; your approval can only stay inside that ceiling or narrow it further.
| Capability | What it allows | Who sets the ceiling |
|---|---|---|
sso |
Sign in to that service as you, and nothing else. It cannot read a single password, note, or 2FA entry. | Registration, then your per-request approval. |
app_data |
Lets the service keep a small encrypted blob of its own. Your device encrypts it; neither the server nor that service's backend sees plaintext. | The service's data_approved flag, plus your approval. |
ap |
Treats the service as an Access Point (AP) that may read entries inside a scope you allow. The scope is limited to 2fa, passwords, and notes. |
Requires KeyLockr admin approval (ap_approved), then your choice of scope. |
ap capability with 2fa in scope may receive short-lived current and next codes after phone approval, but never the seed needed to generate codes indefinitely.
An SSO grant uses (safe_id, app_tag, enc_pk) as its persistent identity; sign_pk is only the current login credential. Normal logout clears that credential while retaining the row and AppData, so approval with a new sign_pk can reconnect it.
That row also holds the envelopes addressed to the service. Deletion stops new delivery, but cannot erase data the service already opened or stored.
Normal logout uses app_logout, which disables only the current login credential and retains the binding. Permanent disconnection uses app_del on the phone that granted access, deleting the row and its envelopes without requiring the other side's cooperation.
Afterwards, KeyLockr refuses later requests and stops delivering new envelopes. If the service saved plaintext or keys before revocation, revocation cannot remotely erase those copies.
What follows is the actual protocol behaviour, not an illustration. Action names, parameters, and limits match the code.
| Item | Specification |
|---|---|
| Handshake address | sso://login?tmp_id=... (white-label) / keylockr://sso?tmp_id=... (branded) |
| Identifying the requester | app_scan_info — returns the registered title and app_tag. A read; it grants nothing. |
| Creating the binding | app_add — writes or reactivates a binding and its envelopes; SSO is identified by (safe_id, app_tag, enc_pk), AP by (safe_id, app_tag, sign_pk). |
| Normal logout | app_logout — clears only the current SSO sign_pk, retaining the app_id, enc_pk, capabilities, and AppData; AP is not supported. |
| Revoking | app_del — deletes the row and envelopes; only the Safe that approved it may run this. |
| The sign-in result | app_auth_result Signed by the KeyLockr server with Ed25519 and sealed with box to the app's enc_pk; the recipient verifies with the server signing public key. |
| Result size limit | 12 KiB. Beyond that the server answers app_auth_result_too_large; nothing is silently truncated. |
| Larger payloads | Switch to data_deferred: the result carries a pointer and the app fetches the body itself with app_get_data / app_set_data. |
| Delivery paths | Both at once: a push down the tmp channel, and the keylockr_result parameter (base64url) on the return URL. The two are byte-for-byte identical. |
| De-duplication | First-valid-wins: keep the first copy that verifies and discard the rest silently. One approval yields one session. |
| Where to verify | Always verify the signature on your backend, never in the UI. The front end's only job is to hand the result to the backend. |
tmp_id |
A one-time handshake address. It is not an account and not a key; once used or expired it means nothing. |
| tmp device | The WebSocket connection opened by a legacy advanced sign-in page. It owns nothing, expires on its own, and losing it costs nothing; Delegated v1 has no such connection. |
capabilities |
The list of named powers you granted — only sso, app_data, and ap exist. Anything not on the list is not permitted. |
app_tag |
The service's identifier, fixed at registration. The name on your approval screen corresponds to it. |
| Ed25519 | The signature algorithm. It proves a frame was signed by a particular private key; change one byte and it no longer verifies. |
| Safe | Your phone. Every approval happens here, and so does every revocation. |
| Access Point (AP) | A consumer allowed to read entries. The phone grants its access and the phone takes it back. |
| KPS | KeyLockr Protocol Suite — the frame format devices speak, always signed on the outside. |