skip to content

Two years into a rented authorization server, what does moving every user onto an issuer you run yourself actually cost you?

level: principalimportance: should knowfreq 30%

answer

  1. price the exit at entry
  2. identities export, proofs do not
  3. subject identifiers are issuer-scoped
  4. standing grants need visible re-consent
  5. dual-run or a single-night flag day

basics

~20 s

Identities export; proofs usually do not. Password hashes and second-factor secrets commonly cannot come across, every local row keyed on the old issuer's subject identifier must be re-keyed, and each standing user grant needs a fresh, user-visible consent.

solid answer

~50 s

Four costs, in rising order of surprise. First, **what does not export**: account attributes generally come out, but password hashes and second-factor shared secrets commonly do not — and a hash you cannot verify with your own parameters is the same problem as one you never received. Second, **the join key**: `sub` is unique only within an issuer, so every local row keyed on the old `sub` has to be re-matched on a verified attribute and re-keyed, which is a data-migration project rather than a configuration change. Third, **re-consent**: a standing grant a user gave at the old issuer does not travel, so every affected person is redirected through a consent screen again — a user-visible event with a drop-off rate. Fourth, **the cutover shape**: if both issuers can be live while users migrate on next sign-in, this is a quiet quarter; if not, it is a flag day with a forced reset behind it.

code

json · 17 lines
json
{
  "export": "users.json — one record per account",
  "record": {
    "iss": "https://login.example.net/",
    "sub": "a7f3c1e2-4b9d-4f61-8c2a-0d5e7b91c3aa",
    "email": "[email protected]",
    "email_verified": true,
    "created_at": "2024-02-11T09:04:00Z",
    "second_factor": { "enrolled": true, "shared_secret": null },
    "password_hash": null
  },
  "not_in_this_export": [
    "password material you can verify yourself",
    "second-factor enrolment secrets",
    "standing authorizations granted at this issuer"
  ]
}

go deeper

for a junior

Remember that moving between authorization servers is not a settings change: user records may come across, but the proofs behind them — passwords and second factors — usually do not, so real people have to act.

for a middle

Be able to explain that a subject identifier is unique only within one issuer, so local rows keyed on it break when the issuer changes. Say what you would store instead to avoid that.

for a senior

Plan it as a migration: what exports, what forces a reset, how users are re-matched and re-keyed without creating duplicates, and when in the year the cutover can safely run. Rehearse the export before you need it.

for a principal

Price the exit at the moment you choose the entry, and put it in the contract: export scope and format, life after termination, and whether a credential-verified dual run is possible at all. That number, not a preference, is what makes the decision reversible.

## Why the exit is priced at entry Choosing an authorization server is cheap to decide and expensive to undo, and the undoing is the part nobody costs until migration day. The exit question is not pessimism about a supplier — the same costs apply moving *between* rented providers, or moving *from* a self-run issuer to a rented one. Ask it on day one, because almost every mitigation below has to be in place years before it is used. Work it against the filing assistant that reads a payroll system on the filer's behalf. Two years of filers, each with a local record, a history, and a standing authorization to read a payroll system on their behalf. A deadline sits on the calendar and cannot move. ## What comes across and what does not - **Account attributes generally export**: an identifier, an email address and its verification status, timestamps, group memberships, and often the fact that someone enrolled a second factor. - **Password hashes are the classic blocker.** Some providers will hand them over in a documented format; many will not, and even when they do, a hash you cannot verify with your own parameters is the same problem as one you never received. If you cannot verify it, those users must reset. - **Second-factor shared secrets are worse**, because the enrolment is a physical act. A secret that cannot be exported means every enrolled person re-enrols, in person with their own device, at a time you choose. - **Sign-in and consent history** may be exportable as a report rather than as data. If you are obliged to retain it, check the format and the retention window *before* you terminate, because access usually ends with the contract. ## The join key problem This is the one that turns a migration into a data project. An OpenID Connect `sub` value is unique **within one issuer**, not globally; the pair of `iss` and `sub` is what identifies a person. A new issuer mints its own `sub` values for the same humans. So every local row keyed on the old `sub` alone has to be re-matched — typically on a verified email address or another attribute you can trust — and re-keyed. Doing that under time pressure is where duplicate accounts are created and where two people are occasionally merged into one. The cheap mitigation costs nothing on day one: store `iss` alongside `sub`, keep a stable internal account identifier of your own that nothing external ever sees, and let every foreign identity hang off that identifier rather than be it. ## Re-consent A standing authorization a person granted to read their payroll data was granted **at the old issuer**, and it does not travel. Under the new issuer, each affected user is sent through consent again — `prompt=consent` is a redirect a human sees and can abandon, not a background job. Budget for it as a funnel with a real drop-off rate, sequence it outside the deadline window, and expect a support wave from people who do not recognise the screen. Anything that silently depended on that standing authorization — a nightly job, a reminder, a pre-filled form — stops for every user who has not yet gone through it. ## Can you dual-run? The single question that decides whether this is a quiet quarter or one bad night: 1. **Both issuers live, lazy migration.** New sign-ins go to the new issuer; anyone who has not moved is still served by the old one and is migrated on next sign-in. Costs: you operate two login paths and accept two identities per person for a while, and you need a rule for the users who never return. 2. **Both live, credential-verified migration.** Where the old provider will verify a credential on request, you can re-hash it under your own parameters at that person's next sign-in and move them invisibly. This is the best outcome and it depends entirely on a capability you must confirm at signing. 3. **Flag day.** No dual run: a single cutover, every password reset, every second factor re-enrolled, every grant re-consented, all at once. Pick the quietest month in the year, over-staff support, and rehearse the rollback — because a cutover you cannot reverse is a cutover you should not run against a statutory deadline. | Cost | Shows up as | Bought down on day one by | |---|---|---| | Non-exportable hashes | A forced reset for every user | An export clause, tested in a rehearsal | | Second-factor secrets | Everyone re-enrols | Offering a factor whose enrolment you hold | | Re-keyed `sub` values | A data migration with duplicates | Your own internal identifier, plus `iss` stored | | Re-consent | A funnel with drop-off | Knowing which grants exist and who depends on them | | No dual run | A flag day with no rollback | Confirming migration support before signing | ## What to do about it now Store `iss` with `sub` and key your rows on an identifier of your own. Get the export clause — data, format, timing, and life after termination — into the contract. Rehearse the export periodically against a scratch environment so you learn what is missing while it is cheap. Keep your own copy of anything you are obliged to retain. Then, whichever way the decision goes, you know the number, and the meeting that revisits it is a comparison rather than an argument.

  • What single schema decision, made on day one, most reduces the cost of this migration?
    Key your account rows on an internal identifier you mint yourself, and hang every external identity off it as an (`iss`, `sub`) pair rather than making the provider's `sub` the primary key. Changing issuers then adds a row to a link table instead of re-keying every record that references an account.
  • How would you sequence a migration when the two issuers cannot run side by side?
    Pick the quietest window in the year, well away from any deadline. Announce it, pre-verify contact details so reset messages land, over-staff support for the wave, and rehearse the rollback first. Treat every enrolled second factor as re-enrolment work, because it requires the person and their device rather than a script.
  • Why does re-consent deserve a line in the migration plan rather than a footnote?
    Because it is a redirect a human must complete, so it behaves like a funnel with drop-off, not like a data job. Until someone finishes it, anything that relied on their standing authorization — background refreshes, scheduled work, pre-filled data — is simply not running for them, and they will not know why.
  • Does this cost apply only when leaving a rented provider?
    No. The same four costs appear moving between two rented providers, and in the other direction when a self-run issuer is retired in favour of a managed one. The direction changes who holds the export; it does not change that identities travel, proofs generally do not, and subject identifiers are issuer-scoped.

saying these in an interview costs you the question

  • Assumes a user export includes usable password material
  • Treats the subject identifier as globally unique across issuers
  • Plans the cutover as a configuration change, not a data migration
  • Forgets that standing grants require fresh, user-visible consent
  • Schedules the migration near the busiest date of the year
  • Never checks whether the two issuers can run side by side