Pairwise subject IDs
The Connect2id server can output pairwise pseudonymous end-user IDs (PPID) in the OpenID Connect ID tokens and UserInfo responses, as well as in minted access tokens.
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. How to register an OpenID relying party for pairwise subjects
An OpenID relying party can obtain the ID of the end-user through the sub
(subject) claim of their ID token and the
sub
field of a UserInfo response.
To make an OpenID relying receive pairwise end-user IDs this must be configured in its registered client metadata.
Note, the pairwise IDs in OpenID Connect ID tokens and UserInfo responses are independent from those in access tokens.
3.1 Simple case
A relying party will receive pairwise subject IDs when it’s registered with the subject_type client metadata parameter set to pairwise. This parameter is optional and when it’s omitted 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. How to issue 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.
Note, the pairwise IDs in access tokens are independent from those in OpenID Connect ID tokens and UserInfo responses.
4. Pairwise IDs in OpenID Connect objects and access tokens
The pairwise IDs in OpenID Connect objects (ID tokens, UserInfo responses) are enabled separately and independently from those in access tokens.
This means that pairwise IDs can be enabled in either or both places.
When pairwise IDs are enabled in both places, they will appear as different values for the relying party (ID token, UserInfo) and the resource server (access token), due to the pairwise algorithm using the audience as one of its inputs.
5. 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.