Self Issued IDs - Draft 2

This is an early exploration of a protocol that uses OPRF to enable identity federation on the Web.

The protocol assumes:

  1. An IDP with a logged in user idᴵᴰᴾ (say, 3) that it desires to keep private.
  2. The IDP's nameᴵᴰᴾ = https://idp.example and a publicᴵᴰᴾ/privateᴵᴰᴾ key pair.
  3. An RP with a nameᴿᴾ = https://rp.example that it desires to keep private.
  4. An agent that is trusted by the RP and the IDP to represent the user's best interest.

At the end of the protocol:

  1. The RP gets a directed idᴿᴾ without learning about the IDP's idᴵᴰᴾ
  2. The IDP never learns the nameᴿᴾ in the exchange
  3. The user is able to reconstruct idᴿᴾ to recover their account without the original agent

The basic idea is to run OPRFs for two things:

  1. first, to generate audᴿᴾ running OPRF∘keyᴿᴾ(nameᴿᴾ) which the IDP can use to define the scope without learning nameᴿᴾ
  2. second, to generate idᴿᴾ running OPRF∘idᴵᴰᴾ(audᴿᴾ) to generate a shared directed identifier without revealing to the RP the global idᴵᴰᴾ


  1. The agent starts by asking and confirming that the user wants the agent to facilitate signing-in to the RP with their IDP account.
  2. If so, the agent starts by generating audᴿᴾ by running OPRF∘keyᴿᴾ(nameᴿᴾ) which is guaranteed to represent the nameᴿᴾ while still making it opaque to the IDP.
  3. The agent constructs a directed identifier idᴿᴾ by running OPRF∘idᴵᴰᴾ(audᴿᴾ) without revealing the idᴵᴰᴾ to the RP (how?).
  4. The agent generates a publicᴬᴳᴱᴺᵀ/privateᴬᴳᴱᴺᵀ key pair.
  5. The agent sends to the IDP:
    1. The idᴿᴾ.
    2. The audᴿᴾ.
    3. The publicᴬᴳᴱᴺᵀ.
  6. The IDP checks if idᴿᴾ hasn't been revoked (see revocation)
  7. The IDP issues a signed JWTᴵᴰᴾ with:
    • subᴵᴰᴾ = idᴿᴾ, a directed identifier
    • audᴵᴰᴾ = audᴿᴾ, scoping to nameᴿᴾ
    • agentᴵᴰᴾ = publicᴬᴳᴱᴺᵀ, delegating the presentation to the agent
    • expᴵᴰᴾ = an expiration time of its choice (see revocation)
    • sigᴵᴰᴾ signed with the privateᴵᴰᴾ
  8. The IDP stores audᴿᴾ
  9. The agent issues a new JWTᴬᴳᴱᴺᵀ:
    • subᴬᴳᴱᴺᵀ = idᴿᴾ
    • audᴬᴳᴱᴺᵀ = audᴿᴾ
    • expᴬᴳᴱᴺᵀ = an expiration time of its choice
    • sigᴬᴳᴱᴺᵀ signed with the privateᴬᴳᴱᴺᵀ
  10. The agent sends the JWTᴬᴳᴱᴺᵀ and the JWTᴵᴰᴾ to the RP.
  11. The RP verifies that:
    1. sigᴵᴰᴾ is signed with publicᴵᴰᴾ
    2. agentᴵᴰᴾ matches the publicᴬᴳᴱᴺᵀ
    3. sigᴬᴳᴱᴺᵀ is signed with a publicᴬᴳᴱᴺᵀ
    4. subᴵᴰᴾ matches subᴬᴳᴱᴺᵀ
    5. audᴵᴰᴾ matches audᴬᴳᴱᴺᵀ
    6. Neither expᴵᴰᴾ nor expᴬᴳᴱᴺᵀ are expired
  12. The RP then runs OPRF∘keyᴿᴾ(nameᴿᴾ) and checks if it matches aud.
  13. The RP uses idᴿᴾ = subᴬᴳᴱᴺᵀ to uniquely identify the user in its service, such that
    • the IDP never learns about nameᴿᴾ and
    • the RP never learns about idᴵᴰᴾ and
    • the agent is confident that idᴿᴾ is directed


  1. In the absence of an agent capable of intermediating this exchange, the IDP plays the role of the agent and asks for the RP to reveal its nameᴿᴾ. It then runs the same Sign-in algorithm described above.


  1. When a user decides to unregister from RP, they revoke idᴿᴾ by asking their agent to tell the IDP to stop renewing JWTᴵᴰᴾ with the for idᴿᴾ.