Approval cards
Every approval card the user sees in MimiKey — when it appears, what it shows, what each button does, the callback status it produces, and how long it stays valid.
Overview
Approval cards are the decision screens MimiKey renders for third-party authorization. Every card runs inside MimiKey's own process (the iOS app and the Mac app). Integrators cannot change a card's structure or buttons; they can only supply the name, icon, brand color and homepage from the branding allowlist.
The MimiKey apps are currently in Chinese. Labels below are given in English with the on-screen Chinese in parentheses.
| Card | Triggered by | Primary button | Secondary button |
|---|---|---|---|
| Consent card | authorize() / mimikey://authorize | Allow (允许) | Deny (拒绝) |
| Pick card | pick_item | Use this item (用这条) | Don't share (不给) |
| Read approval card | get_item (ask policy) | Allow once (允许一次) | Deny (拒绝) |
| Safety card (create) | create_item | Save and use for this task (保存并用于本次任务) | Not now (不用了) |
| Update card | update_item | Save changes (保存修改) | Deny (拒绝) |
Checks before a card appears
When MimiKey receives a deep link it checks, in order:
- Account state. If no account is signed in, MimiKey shows a "Sign in to MimiKey first" card; Return to app sends the callback
error=not_signed_in. If the account is signed in but locked, MimiKey runs its normal unlock (Face ID, Touch ID or master password) and then shows the card. If MimiKey locks while a card is open, the card is put away and shown again after unlock. - Deep-link parameters. If the redirect URL itself is malformed, MimiKey does not navigate anywhere and only shows a notice. Any other missing or malformed parameter produces the callback
error=invalid_request. - Client and redirect URL. An unknown client, a client disabled by its developer or by the platform, or a redirect URL that is not registered produces
error=invalid_request. - Request. A request that does not exist or does not belong to the signed-in account produces
error=request_not_found.
Common card layout
Every card contains, top to bottom:
- MimiKey mark — identifies the screen as rendered by MimiKey itself.
- Integrator brand block — icon (the first letter of the name if the icon fails to load), name and homepage domain. On iOS, public clients also carry an "in-app" (设备内应用) badge.
- Title — starts with the integrator's name and says what it wants.
- Purpose — the integrator's
reason, shown verbatim. - Expiry countdown — when it reaches zero the card closes and the callback reports
status=expired. - Action buttons — two fixed buttons whose meaning is defined by MimiKey.
Consent card
Triggered by: the integrator calling authorize(), which opens mimikey://authorize.
Shows:
- Title: "{App} requests a connection to your MimiKey" (on Mac: "{App} wants to connect to your MimiKey").
- "What it will be able to do", four lines: read the items you choose, ask you to pick an item, ask you to create items in MimiKey, ask you to approve changes.
- "Vaults to grant": only vaults you own are listed, with your personal vault checked by default. A regular member of a shared vault cannot grant it.
- "Approval policy": Ask every time (每次询问, default) or Trust this app (信任此应用), annotated "Reads no longer ask each time, but still run when you open MimiKey".
- "Approval-key fingerprint": 16 hex characters. The integrator's app can display the same fingerprint for you to compare.
Outcomes:
| Action | Result | Callback |
|---|---|---|
| Allow | An authorization code is issued (10 minutes, single use) | ?mk=authorize&code=…&state=… |
| Deny | No grant is created | ?mk=authorize&error=access_denied&state=… |
The grant takes effect only once the code has been exchanged for tokens.
Pick card
Triggered by: a pick_item request.
Shows:
- Title: "{App} wants you to pick an item", plus the purpose.
- Candidates: every item in the granted vaults (or in the one vault the request names), ordered by the integrator's hint — same registrable domain first, then title match, then same item kind.
- A search field that filters by name, account or URL.
- Each row shows the kind icon, title and subtitle. Passwords are never shown.
Outcomes:
| Action | Result | Callback status |
|---|---|---|
| Select an item, then Use this item | The item is decrypted on the device, sealed for the integrator and uploaded; the request completes | completed |
| Don't share | The request is denied | denied |
The integrator also receives a plaintext receipt, picked_item (id, title, url, kind), which never includes the password or notes.
Read approval card
Triggered by: a get_item request.
ask policy: titled "{App} wants to read '{item title}'", with the vault and purpose below.
| Action | Result | Callback status |
|---|---|---|
| Allow once | Approved and executed on this device immediately; the request completes | completed |
| Deny | The request is denied | denied |
trust policy: the request is approved as soon as it is created. Opening MimiKey executes it directly; the card only flashes "Provided per your trust setting" (已按你的信任设置提供) and returns to the integrator. If no unlocked device is available, the request waits as "approved, waiting for a device" until you unlock MimiKey or it expires.
Note Trust only removes per-read approval. Picking, creating and updating always require you to act on the card, under either policy.
Safety card (create)
Triggered by: a create_item request.
Shows:
- Title: "{App} wants you to create a {kind}", plus the purpose.
- The full edit form for that kind (login, credit card, bank card, API key, server, secure note), prefilled with the integrator's title, URL, username and other hints, all editable. You type the password here; the integrator never handles it.
- "Save to": defaults to the vault named in the request; you can pick any vault you own. Vaults outside the grant are labelled "outside grant" (授权范围外).
Outcomes:
| Action | Result | Callback status |
|---|---|---|
| Save and use for this task (into a granted vault) | The item is encrypted and saved; saving approves this use, and the integrator receives the full item | completed |
| Save and use for this task (into a vault outside the grant) | The item is saved as usual, but the integrator only receives a receipt (saved_out_of_scope) and cannot read the item; the grant is never widened | completed |
| Not now | The request is denied and nothing is saved | denied |
The card blocks submission while required fields are empty. Once saved, the item is indistinguishable on the server from one you created by hand — ciphertext only.
Update card
Triggered by: an update_item request, after the integrator uploads its encrypted patch.
Shows:
- Title: "{App} wants to change '{item title}'", plus the purpose.
- A diff table: each changed field has an old (原) and a new (新) row. Password-type fields are masked by default, with Show / Hide (显示 / 隐藏).
- The current revision, noting that saving creates a new revision.
New values are sealed by the integrator to your account identity public key, so only your unlocked device can read them. If the patch contains a field the request did not declare, MimiKey rejects the request.
Outcomes:
| Action | Result | Callback status |
|---|---|---|
| Save changes | A new revision is written; the integrator receives only the new revision number, never plaintext | completed |
| Deny | The request is denied and nothing is written | denied |
| (The item changed elsewhere before saving) | The card says the item was just changed elsewhere and the change was not saved; the request ends as denied | denied |
Leaving without acting
If you switch back to the integrator's app without doing anything in MimiKey (pressing Esc to close the card on Mac has the same effect), MimiKey sends no callback and the request stays pending until it expires. The integrator's waiting screen offers Retry (reopen MimiKey on the same card) and Cancel.
Expiry
| Object | Lifetime | On expiry |
|---|---|---|
| Authorization code | 10 minutes, single use | Exchange fails (code_expired) |
| Pick and read requests | 10 minutes | expired |
| Create requests | 30 minutes | expired |
| Update draft (waiting for the integrator's patch) | 60 seconds | expired; never reaches your devices |
| Update request (after the patch) | 30 minutes | expired |
| Access token | 1 hour | The integrator refreshes automatically |
| Refresh token | 30 days, renewed on every refresh | The user must authorize again |
Card countdowns match the server's expiry times. When a grant is revoked, all of its unfinished requests become expired immediately.
Callback summary
| Situation | Callback parameters |
|---|---|
| Authorization succeeded | mk=authorize&code=…&state=… |
| Authorization declined | mk=authorize&error=access_denied&state=… |
| Request completed | mk=request&request_id=…&state=…&status=completed |
| Request denied, cancelled or expired | mk=request&request_id=…&state=…&status=denied (or cancelled, expired) |
| MimiKey not signed in | error=not_signed_in |
| Invalid deep link or client | error=invalid_request |
| Request not found | error=request_not_found |
A callback only tells the integrator that it can fetch the result; it never carries result data.
Managing access in MimiKey
Besides cards opened from deep links, you can work directly in MimiKey:
- iOS: Settings → Third-party access (第三方授权).
- Mac: Third-party access (第三方授权) in the sidebar.
There are two parts:
- Pending requests — everything waiting for you. Opening one shows the same approval card as the deep link. When you finish, the card simply closes without switching to the integrator's app; the integrator picks up the result by polling.
- Authorized apps — each grant's app name, granted vaults, approval policy and approval-key fingerprint. You can switch between Ask every time and Trust this app (affects only new requests) or revoke the grant. Revocation is immediate: all of the app's tokens stop working and every unfinished request expires.