Self Issued IDs

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ᴵᴰᴾ = 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 run an OPRFᴿᴾ(idᴵᴰᴾ) to generate a shared directed idᴿᴾ identifier without revealing to the RP the global idᴵᴰᴾ
  2. second, to run an OPRFᴵᴰᴾ(nameᴿᴾ) to generate an audᴵᴰᴾ that the IDP can use to limit the scope of idᴿᴾ without learning nameᴿᴾ

In this protocol, we'll also decouple the issuing of credentials with their presentation, by delegating presentation to a capable agent.


  1. The procotol starts by the IDP sending the idᴵᴰᴾ to the agent
  2. The agent constructs a directed identifier idᴿᴾ by running idᴿᴾ = OPRFᴿᴾ(idᴵᴰᴾ) without revealing the idᴵᴰᴾ to the RP (how?).
  3. The agent constructs an audᴵᴰᴾ by running audᴵᴰᴾ = OPRFᴵᴰᴾ(nameᴿᴾ) to represent the nameᴿᴾ without revealing it to the IDP (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 agent issues a new JWTᴬᴳᴱᴺᵀ:
    • subᴬᴳᴱᴺᵀ = idᴿᴾ
    • audᴬᴳᴱᴺᵀ = audᴵᴰᴾ
    • expᴬᴳᴱᴺᵀ = an expiration time of its choice
    • sigᴬᴳᴱᴺᵀ signed with the privateᴬᴳᴱᴺᵀ
  9. The agent sends the JWTᴬᴳᴱᴺᵀ and the JWTᴵᴰᴾ to the RP.
  10. 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
  11. The RP then runs OPRFᴵᴰᴾ(nameᴿᴾ) and checks if it matches aud.
  12. 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ᴿᴾ.