Skip to main content

Sessions, grants, and keys

When you sign in to something with your DFOS identity, a session starts somewhere. Where that somewhere is decides whether DFOS can show it to you and end it for you. What decides that, underneath, is which key signed — so this page covers both: the two planes a session can live on, and the three kinds of key that put it on one or the other.

There are two planes, and only one of them appears in your settings.

Grants the platform manages

This is what happens when you press a "Sign in with DFOS" button on another app. DFOS holds a platform key for you, so DFOS does the signing: it renders the consent screen, signs the app's challenge with that key, and — if you approved a scope that issues one — mints the app's credential. An app can ask for several scopes at once; it still gets one credential, covering everything you approved.

Because the platform issued it, the platform can end it:

  • Settings → Connected apps lists every standing grant, the app it went to, and what that app is allowed to read — one line per thing, the same lines you read on the consent screen.
  • Disconnecting one app, or all of them at once, revokes on the spot. Revocation is checked on the app's next API request, which then fails. You are not waiting out a cached token.
  • Grants carry a 90-day expiry, shown on each card — 14 days for a local application, which has no domain DFOS could re-check later. Either way that is a backstop for grants nobody got around to revoking. It is not the lever you use to end access.

Revoking ends future access. It does not un-share what the app already read, so disconnect when you're done with an app rather than as cleanup later.

Trusting an app to skip the screen

On the consent screen there's a checkbox: "Trust this app — skip this screen next time." Tick it and the next sign-in to that app shows a short card instead of the full one — who's asking, who you are, what it already has, Approve and Deny.

Trusting an app grants it nothing. Every check DFOS runs on a sign-in runs exactly the same way whether you trusted the app or not. The only thing that changes is how much of the screen you're asked to read again. An app that stops being able to prove who it is gets refused whether you trusted it or not.

Three things bring the full screen back:

  • The app asks for something new. More than you approved last time means you read and approve the new part. Asking for less than last time doesn't — you already said yes to more.
  • The app's identity changes. If a different identity starts answering for a domain you trusted, DFOS removes your trust before showing you anything, and the screen leads with the change: the identity you trusted, struck through, against the one asking now. That can be a routine key change on the app's side, or a domain that changed hands. Read it before you approve.
  • You remove the trust yourself.

In Settings → Connected apps, a trusted app is marked Trusted and carries a Remove trust button. Removing trust ends nothing — the app keeps whatever you granted it, and simply asks for full approval next time. Disconnect is the lever that actually ends access, and disconnecting removes the trust too.

Apps running on your own machine can be trusted only if they proved which identity they are. One that proved nothing about itself can never be trusted, because there'd be nothing for the trust to be about — and it would silently apply to the next anonymous program on that machine.

A tool on your own machine can be on this list too

Most cards on Connected apps name a domain. Some say Local application instead, and those are command-line tools, agents, and desktop apps that signed in from your own machine.

They belong here for the same reason every other card does: DFOS held your key and did the signing, so DFOS issued something and can end it. The card leads with "Local application" and the tool's identity address rather than a domain, because there is no domain — what the platform checked is that the tool holds the key it asked to be addressed as, and nothing about where the software came from. Revoke one exactly as you would any other.

DFOS emails you when this list changes

Three moments send you mail, so a change to what apps hold on your behalf reaches you out-of-band rather than only on a screen you'd have to think to open:

  • An app connected — sent when you approve a sign-in, naming the app's domain and listing what you granted, one line per thing.
  • An app was disconnected — sent when you disconnect a single app.
  • All apps were disconnected — sent when you disconnect everything at once.

The connect email is the one that matters most: if it arrives and you did not approve anything, someone else reached your account, and disconnecting is the first move. That is the security property these exist for, which is why they are sent rather than offered as a preference.

Each disconnect email says the same thing the screen does: access ends on the app's next request, not at some later expiry.

Sessions the platform never sees

The Connected apps list shows exactly what the platform issued — and only that.

The protocol underneath doesn't require us. A sign-in is a signed challenge, and any app can verify one for itself by resolving your identity chain and checking the signature against it. When the signing key is one you hold rather than one DFOS holds, DFOS is never in that loop: nothing is issued here, nothing is recorded here, and there is nothing here to revoke.

What decides the plane is whose key signed, not what kind of software asked. A tool running against a relay with a key you hold yourself sits here, invisible to us. That same tool signing you in with your DFOS identity does not — DFOS held the key, so the grant is on the list above as a local application. Command-line tools appear on either plane depending on which they used.

The sessions on this plane are real. They are managed wherever they were created — in the app or tool that established them — and that is where you end one.

So read the list for what it is: an empty Connected apps screen means DFOS is holding no standing grants on your behalf. It is not a statement about every session that exists in your name.

The three kinds of key

Your DFOS identity is a signed chain of operations, published to a public relay and verifiable by anyone who can read it. None of that requires our servers — the chain is the identity, and the keys that sign it are the authority. See The protocol.

Three kinds of key can sign for your identity, and they are kept apart on purpose. You see all of them in Settings → DFOS Protocol.

KeyWho holds itWhat it can do
Platform keyDFOSSigns on your behalf, in the app and at the consent screen
Signing keyYouSigns in as you, and signs claims as you
Exit keyYouChanges the identity chain itself

Platform keys

A platform key is one DFOS holds and signs with on your behalf. You never handle it and there is nothing to set up — your account has one from the moment it exists.

That custody is what makes the ordinary product work. It is why you can sign in with a code sent to your email rather than a key file, and it is why the platform can both mint a grant for an app and revoke it for you. Every standing grant on Connected apps was signed by a platform key, which is exactly why that list is a list DFOS can show you.

Signing keys

A signing key is one you hold, on your own machine, added to your identity's chain. DFOS never sees its private half.

It carries two roles: it can sign you in to things as you, and it can sign claims — content, attestations — as you. It cannot change the chain itself; only an exit key does that. A tool signing with your signing key is on the plane DFOS never sees: nothing is issued here and there is nothing here to revoke.

Each key on the list carries a label you choose (typically the machine it lives on), and you can rename or remove one at any time. Removing a key ends what it can sign for.

Adding one

Adding a signing key is a two-sided ceremony, because two different things have to be true: the machine has to prove it holds the key, and you have to confirm it is a key you meant to add. Neither half is sufficient alone.

  1. In Settings → DFOS Protocol, start adding a key. DFOS shows an eight-character code, good for ten minutes, and the command to run:

    dfos keys add api.dfos.com/K7M2QXPA
  2. Run it on the machine the key should live on. The CLI resolves the code, shows you which identity the key would join — the DID, the handle, the display name — and asks you to confirm before it signs anything. It then signs a small envelope proving it holds the key and sends that to DFOS. The private half never leaves the machine; what travels is a public key and one signature.

  3. Nothing is on your chain yet. DFOS verifies the envelope and stops there. Back in settings, the pending key appears with its fingerprint rendered as a short phrase of words — the same phrase the terminal printed. Compare them.

  4. If they match, adopt the key; that is the step that appends the operation to your chain, and it is the first moment the key means anything. If you do not recognize it, reject it. A code carried to the wrong terminal therefore adds nothing to anybody's chain — it produces a key its owner does not recognize and declines.

If the ten minutes run out before anyone adopts or rejects, the ceremony simply expires and nothing was added. Developers building against the CLI-facing half of this want Key proof.

Exit keys

An exit key is one you hold in the controller role — the role that can change an identity chain itself, rather than merely sign with it. That is the only role it gets, and adding one is a separate, heavier ceremony than adding a signing key, because of what the role carries.

DFOS cannot use this key — your identity chain here is projected from platform state, and no exit key writes to it. An exit key exists so this identity can continue beyond DFOS.

Two consequences worth stating plainly:

  • It is never checked for activity. DFOS does not poll it, does not warn you that it has gone unused, and does not treat a dormant exit key as a problem to fix. An exit key you never use is an exit key doing its job.
  • It is only useful if you still have it. Keep it somewhere you would still reach if you lost access to this account — that is the case it is for.

The recovery drill

The second point is the one worth testing, and it is testable without waiting for the day you need it. A seed phrase you have never restored from is a hypothesis; restoring from it is how it becomes a fact.

Do it somewhere disposable rather than on the machine that already holds your keys. An ephemeral environment — a container, or a spare machine you can wipe — gives you a clean home directory with no vault and no config, which is exactly the position you would be recovering from for real:

docker run --rm -it -e HOME=/tmp/drill debian:stable-slim

Install the CLI there, then ask what a recovery would bring back:

dfos recover --dry-run

--dry-run walks the whole recovery and stops short of writing: it derives keys, fetches chains and verifies them in memory, and reports exactly what a real run would restore — without touching a vault, a config file, or a local relay. When the container exits, everything you just derived goes with it.

What you are checking is that the phrase produces the identity you expect and the chain behind it comes back whole. If it does, the way out is real. If it does not, you have found that out on a Tuesday instead of on the worst day.

Checking a machine you already use

The drill above is for the phrase. For a machine that already holds keys, "am I still good" is two questions — is this machine's copy of the chain current, and do I still hold the keys — and one command answers both:

dfos identity status <your-did>

The verdict comes first. in-sync means the relay's log and this machine's are the same operations in the same order; the others — behind, ahead-unpublished, diverged — each name a specific disagreement rather than a failure.

Under it is the possession roster: one row per key the chain declares, with its id, its roles, and where its private half is. A row reading held (vault '…' — derivable from phrase) is a key a written-down phrase can mint again; held (standalone) is a key this keystore is the only copy of; not held on this machine is one you cannot sign with from here, whatever the chain says about it — which is exactly the thing worth knowing before you need it. Roles marked (void) are declared and never proved; they resolve nowhere.

The roster names the head it was folded from, and that matters: the same DID under two histories declares two rosters, so the rows are only true of the chain the line above them names.

Both halves have to come from the machine itself. The chain is public and DFOS can show it to you; possession is local, and nobody but the machine can answer it — so run this on the machine that should hold the key. Once you know a key is there, dfos keys show goes further into that one key's detail. Full options are in the CLI documentation.

Why it splits this way

The plane a session lands on follows from which of those keys signed it. A platform key means DFOS did the signing, so DFOS issued something and can end it, and the grant is on Connected apps. A signing key you hold means DFOS was never in the loop, so there is nothing here to list and nothing here to revoke.

So the more of your own keys you use, the more of your sessions live on the plane DFOS cannot see. That is the design working rather than a gap in it, but it does mean one list will never be the whole picture.

  • Agents & connected apps — what a connected agent and an app sign-in each get, and how they differ.
  • Accounts — your identity, your profile, and the privacy controls around them.
  • Scopes and credentials — the developer side: how a credential is issued, spent on each request, and revoked.
  • Key proof — the developer side of the signing-key ceremony: the two API routes a CLI talks to while a key is being added.