Pairwise (encrypted) subject identifiers in ID tokens and access tokens

The Connect2id server can issue ID tokens as well as access tokens with pairwise end-user IDs.

What is the purpose of pairwise identifiers?

  • Confidentiality -- To hide (encrypt) the local end-user ID from the recipient. The local user identifiers may contain sensitive or personal information, for example if based on the user's email address.

  • Prevent correlation -- As part of a strategy to minimise the possibility for linking user identities across token recipients.

    In ID tokens, for a given end-user the pairwise sub will be a different but stable identifier (hence the name pairwise) computed for each OpenID relying party. For example, for some user with local ID "alice" client_id=123 will receive an ID token with sub=naeta7jee4eTu5aiquiphu and client_id=456 will receive sub=IeToonahquiiCaisaema6o.

    Similarly, in access tokens, for a given end-user the sub will differ for each resource server, identified by the token's audience.

    In order for that strategy to work the recipients, OpenID relying parties or resource servers, must not be provided with user attributes that would otherwise enable linking, such as the user's email address. Note, even then there may be opportunities for correlation, if third-party cookies are enabled in the browser, or other pathways to link data can be exploited.

1. Connect2id server configuration

Set the op.pairwiseSubjects.padLocalSubjectsToLength configuration property to the maximum expected length of the local user IDs. This is needed to ensure a uniform length of the computed pairwise subjects.

For example, if the local user IDs have lengths up to 10 characters:

op.pairwiseSubjects.padLocalSubjectsToLength=10

Example pairwise IDs for local subjects "alice", "bob" and "claire" with padding set up to 10 characters:

pxXoRPqPpLy3fBbLNV22KRCghztrFMtGV3AxDnQH_erfB4dwZ_0
s10h_EEMtYHaNSZuMBznfvupKqC2mznkIGnmxRevffJGo4ybRrM
uLfwVCpRUu1ltEeXqRt_Yik7SN5-yKabYwXan-xYCwgJlDZubSA

With disabled padding (set to -1), notice how information about the local subject length is leaked:

myzM-ARj7vYBH9NOIog9Sf5xklhU_rkLenu8mOtfLv6L
Q20o2EYNsamhlOh2RbteNp7Te7AilmMPVk3cyhmCBA
rNW4ByxEQd06rNCLLMvH2-d1WRumrJcSrmDGA6FlvtxeGw

2. How to find out if an OpenID provider supports pairwise subjects?

Developers can find out if an OpenID provider supports pairwise subjects in ID tokens and UserInfo responses by examining the subject_types field in its published metadata ("public" means regular IDs):

HTTP/1.1 200 OK
Content-Type: application/json

{
  "issuer"                  : "https://c2id.com",
  "subject_types_supported" : [ "public", "pairwise" ],
  ...
}

There is no standard metadata field to indicate support for pairwise subjects in access tokens.

3. Registering an OpenID relying party for pairwise subjects

3.1 Simple case

Relying parties to receive pairwise subject IDs must be explicitly registered for that, by setting the optional subject_type parameter to pairwise. In the absence of that the default action is to register the relying party for plain (public) IDs.

Here is an example minimal registration:

POST /clients HTTP/1.1
Host: c2id.com
Authorization: Bearer ztucZS1ZyFKgh0tUEruUtiSTXhnexmd6
Content-Type: application/json

{
  "redirect_uris" : [ "https://client.example.org/callback" ],
  "subject_type"  : "pairwise"
}

Important: The computation of the pairwise ID uses the host component of the registered redirection ID as an input parameter called "sector ID". If the redirection URI is updated and the host components changes with that, the issued pairwise IDs for all end-users will also change!

Redirection URI: https://client.example.org/callback
Host component / sector ID: client.example.org

3.2 Allowing for change of host component with a sector ID

3.2.1 The standard approach

If a relying party anticipates changes of the host component, or requires multiple redirection URIs with different host components, it creates a JSON document containing an array with all registered redirection URIs.

Example:

[
  "https://abc.example.org/callback",
  "https://def.example.org/callback",
  "https://ghi.example.org/callback"
]

The relying party makes the JSON document available at an HTTPS URL that can be accessed by the Connect2id server (within the configured HTTP connect and read timeouts).

The Connect2id server will then use the host component of the document URL to compute the pairwise IDs (instead of the host component of the redirection URI).

URL: https://example.org/redirect-uris.json
Host component / sector ID: example.org

The relying party must register the URL of the document in the sector_identifier_uri parameter:

POST /clients HTTP/1.1
Host: c2id.com
Authorization: Bearer ztucZS1ZyFKgh0tUEruUtiSTXhnexmd6
Content-Type: application/json

{
  "redirect_uris"         : [ "https://client.example.org/callback" ],
  "subject_type"          : "pairwise",
  "sector_identifier_uri" : "https://example.org/redirect-uris.json"
}

2.2.2 With OpenID provider managed sector ID URNs

The hosting of the JSON document can be an issue for some relying parties. An OpenID provider may also want to exercise tighter control over the assignment and management of the host component input into the pairwise ID computation. To address those cases Connect2id server 12.0 introduced support for OpenID provider managed sector IDs.

For those relying parties the OpenID provider can manage the sector IDs internally, in some a database or portal, by assigning unique sector ID URNs to them prior to registration. Those URNs will not get resolved and validated in the same way a standard https URL in the "sector_identifier_uri" parameter gets, by downloading the JSON document from the URL. Instead, the URN will be used to provide the sector ID directly. The expected URN format is urn:c2id:sector_id:<id> where <id> represents the sector ID assigned to a relying party or group of relying parties under single administrative control.

To use this feature the op.reg.enableProviderManagedSectorIDs configuration property must be turned on.

The client registration POST or PUT request must be authorised with a master API token or one-time registration token with a "client-reg:set-sector-id-urn" scope value. Unauthorised requests (if open registration is allowed) cannot use sector ID URNs.

Example:

POST /clients HTTP/1.1
Host: c2id.com
Authorization: Bearer ztucZS1ZyFKgh0tUEruUtiSTXhnexmd6
Content-Type: application/json

{
  "redirect_uris"         : [ "https://client.example.org/callback" ],
  "subject_type"          : "pairwise",
  "sector_identifier_uri" : "urn:c2id:sector_id:org_123"
}

3. Issuing access tokens with pairwise subject IDs

Starting with Connect2id server 12.0 access tokens can also be issued with subject IDs made pairwise for the intended resource server.

In the browser-based flows make sure the handler sets the access_token.sub_type of the consent object to PAIRWISE. An audience for the token must also be specified, to serve as sector ID in the pairwise subject computation. If multiple audience values are set the first in the list will be used.

Example consent:

{
  "scope"         : [ "read", "write" ],
  "audience"      : [ "https://api.example.com" ],
  "access_token"  : { "sub_type" : "PAIRWISE" }
}

When introspected the access token will have its sub set to a pairwise ID instead of the local user ID.

4. How does the Connect2id server implement pairwise IDs?

The Connect2id server computes the pairwise IDs by applying deterministic AES/SIV-mode encryption over a string composed of the sector ID and the local subject ID (padded if necessary).

pairwise_sub = SIVAES(sector_id|local_sub)

The encryption key is the secret key with ID subject-encrypt from the configured server JWK set.

Important: If the subject encryption key or the configured padding length change, all computed pairwise IDs will change too! To keep the same pairwise IDs make sure the key and the padding length remain the same across server updates.

The pairwise ID can be decrypted, or reversed, with the secret key. The Connect2id server can perform such reversal internally, when processing authorisation requests with the id_token_hint parameter, or UserInfo requests with a pairwise sub in the access token.

5. JWT-encoded access tokens

If a relying party registered for ID tokens with pairwise subjects is issued with a JWT-encoded access token, the JWT will be always encrypted after signing, with the configured AES key from the server JWK set.

This is done to prevent the client from finding out the local end-user ID by inspecting the sub parameter of the signed JWT.

If you have resource servers that expect JWT-encoded access tokens the AES key must be shared with them in order to decrypt the token.

6. Reversing a pairwise ID

For debugging or other needs the pairwise ID can be reversed (decrypted) to find out the underlying end-user ID. This requires the subject encryption key.

6.1 Command line tool

We provide a simple command line tool to encrypt / decrypt pairwise IDs:

https://bitbucket.org/connect2id/pairwise-subject-codec/src/master/

The download section has a compiled JAR for the tool.

6.2 Java OpenID Connect SDK

You can also utilise the OpenID Connect SDK, check out the SIVAESBasedPairwiseSubjectCodec class.