R. Hedberg, Ed.
independent
A. Solberg
Uninett
S. Gulliksson
Schibsted
M. Jones
Microsoft
J. Bradley
Yubico
February 15, 2019

OpenID Connect Federation 1.0 - draft 07
openid-connect-federation-07

Abstract

The OpenID Connect standard specifies how an Relying Party (RP) can discover metadata about an OpenID Provider (OP), and then register to obtain RP credentials. The discovery and registration process does not involve any mechanisms of dynamically establishing trust in the exchanged information, but instead rely on out-of-band trust establishment.

In an identity federation context, this is not sufficient. The participants of the federation must be able to trust information provided about other participants in the federation. OpenID Connect Federations specifies how trust can be dynamically obtained by resolving trust from a common trusted third party.

While this specification is primarily targeting OpenID Connect, it is designed to allow for re-use by other protocols and in other use cases.


Table of Contents

1. Introduction

This specification describes how two entities that would like to interact can dynamically fetch and resolve trust and metadata for a given protocol through the use of third party trust issuers. A trust issuer is an entity whose main purpose is to issue statements about entities, such as OpenID relying party and providers. An identity federation can be realized using this specification by the use of one or more levels of trust issuers. This specification does not mandate a specific way or restrict how a federation may be built. Instead, the specification provides the basic technical trust infrastructure building blocks needed to build a dynamic and distributed trust network such as a federation.

All entities in an OpenID Connect federation MUST have a globally unique identifier.

Note that a company, as with any real-world organization, may be represented by more than one entity in a federation.

OpenID Connect Federation trust chains rely on cryptographically signed JWT documents, and the trust chain does not at all rely on TLS in order to establish trust.

1.1. Requirements Language

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.

1.2. Terminology

This specification uses the terms "Claim Name", "Claim Value", "JSON Web Token (JWT)", defined by JSON Web Token (JWT), the terms "OpenID Provider (OP)" and "Relying Party (RP)" by OIDC core

This specification also defines the following terms:

Entity
Something that has a separate and distinct existence and that can be identified in a context.
Entity statement
An entity statement is issued by an entity, and concerns a subject entity and leaf entities. An entity statement is always a signed JWT.
Intermediate entity
A entity that issues an entity statement that appears somewhere in between those issued by the trust anchor and the leaf entity in a trust chain.
Leaf Entity
An entity defined by a certain protocol. E.g. OpenID Provider/Relying Party.
Trust Anchor
An entity that represents a trusted third party.
Trust Chain
A sequence of entity statements that represents a trusted chain starting at a leaf entity and ending in a trust anchor.

2. Components

2.1. Entity Statement

An entity statement is issued by an entity and concerns a subject entity and leaf entities in a federation. An entity statement is always a signed JWT. All entities in a federation MUST be prepared to publish an entity statement about themselves.

An entity statment is composed of the following claims:

iss
REQUIRED. The entity identifier of the issuer of the statement. If the iss and the sub are identical, the issuer is making a statement about itself.
sub
REQUIRED. The entity identifier of the subject
iat
REQUIRED. The time the statement was issued. Its value is a JSON number representing the number of seconds from 1970-01-01T0:0:0Z as measured in UTC until the date/time. See RFC 3339 for details regarding date/times in general and UTC in particular.
exp
REQUIRED. Expiration time on or after which the statement MUST NOT be accepted for processing. Its value is a JSON number representing the number of seconds from 1970-01-01T0:0:0Z as measured in UTC until the date/time.
jwks
REQUIRED. A JSON Web Key Set (JWKS) representing the public part of the subject entity's signing keys. The corresponding private key is used by leaf entities to sign entity statements about themselves, and intermediate entities to sign statements about other entities. The keys that can be found here are primarily intended to sign entity statements, and should not be used in other protocols.
authority_hints
OPTIONAL. A JSON object where the keys are the entity id's of the intermediate entities that may issue an entity statement about the issuer entity. The value MUST be a JSON array of entities that are further up in the trust chain. The array may be an empty list. The JSON array can be used to simplify the selection of trust chains without the need for following all possible trust chains.
metadata
OPTIONAL. JSON object including protocol specific metadata claims that represent the issuers metadata. The keys of the JSON object represent the metadata type identifier, and their value MUST be a JSON object representing the metadata according to the metadata schema of that metadata type. An entity statement may contain multiple metadata statements, but only one for each metadata type.
metadata_policy
OPTIONAL. JSON object that describes a metadata policy. The keys of the JSON object are the metadata type identifier, and their value MUST be a JSON object representing the metadata according to the metadata schema of that metadata type. An entity statement may contain multiple metadata statements, but only one for each metadata type. If the metadata type identifier is federation_entity then the policy MUST be applied to the immediate subordinate in the trust chain unless that is a leaf entity.
sub_is_leaf
OPTIONAL. Boolean value that indicates whether the subject is considered a leaf entity. A leaf entity is not trusted to issue policy statements about other entities. If this property is left out, it is considered to be false.

The entity statement is signed using the private key of the issuer entity, in the form of a JSON Web Signature (JWS).

Non-normative example of a entity statement, before serialization and adding a signature.

{
  "iss": "https://feide.no",
  "sub": "https://ntnu.no",
  "iat": 1516239022,
  "exp": 1516298022,
  "metadata_policy": {
    "openid_provider": {
      "issuer": {"value": "https://ntnu.no"},
      "organization_name": {"value": "NTNU"},
      "id_token_signing_alg_values_supported":
        {"subset_of": ["RS256", "RS384", "RS512"]}
    },
    "openid_client": {
      "organization_name": {"value": "NTNU"},
      "grant_types_supported": {
        "subset_of": ["authorization_code", "implicit"]},
      "scopes": {
        "subset_of": ["openid", "profile", "email", "phone"]}
    }
  },
  "jwks": {
    "keys": [
      {
        "alg": "RS256",
        "e": "AQAB",
        "ext": true,
        "key_ops": ["verify"],
        "kid": "key1",
        "kty": "RSA",
        "n": "pnXBOusEANuug6ewezb9J_...",
        "use": "sig"
      }
    ]
  },
  "authority_hints": {
    "https://edugain.org/federation": [
      "https://edugain.org/federation"
    ]
  }
}

2.2. Trust chain

In an OIDC Identity Federation, entities that together build a trust chain can be categorized as:

Trust anchor
An entity that represents a trusted third party
Leaf
In an OIDC Identity federation an RP or an OP
Intermediate
Neither a leaf nor a trust anchor

A trust chain begins with a leaf entity's self-signed entity statement, has zero or more entity statements issued by intermediates about subordinates, and ends with an entity statement issued by the trust anchor about the top-most intermediate (if there are intermediates) or the leaf entity (if there are no intermediates) and finally a self-signed entity statement about the trust anchor.

A simple example: If we have an RP that belongs to organisation A who is a member of federation F, the trust chain for such a setup will contain the following entity statements:

  1. A self-signed entity statement about the RP published by the RP
  2. An entity statement about the RP published by Organisation A
  3. An entity statement about Organisation A published by Federation F
  4. A self-signed entity statement about Federation F published by Federation F.

A trust chain MUST always be possible to order such that: If we name the entity statements ES[0] (the leaf entity's self-signed entity statement) to ES[i] (the trust anchors self-signed entity statement), i>0 then:

The signing key that MUST be used to verify ES[i] is distributed from the trust anchors to the leaf entities in some secure out-of-band's way not described in this document.

3. Metadata

The OpenID Connect Federations specification does allow new metadata types to be defined, to support use cases outside OpenID Connect. The metadata type identifier will uniquely identify which metadata specification to interpret.

The metadata document MUST be a JSON document. Beyond that there is no restriction.

Metadata used in OpenID Connect Federations typically re-uses existing metadata standards. If needed, the metadata schema is extended with additional properties relevant in a federated context.

3.1. RP Metadata

The metadata type identifier is openid_client.

All parameters defined in section 2 of OpenID Connect Dynamic Client Registration 1.0 are allowed in a metadata statement.

To that list is added:

organization_name

OPTIONAL. A human readable name representing the organization owning the RP.

3.2. OP Metadata

The metadata type identifier is openid_provider.

All parameters defined in section 3 of OpenID Connect Discovery 1.0

In addition the following properties are allowed:

organization_name

OPTIONAL. A human readable name representing the organization owning the OP. It is intended to be used in the user interface, being recognized by the end users that would be using the OP to authenticate.
federation_registration_endpoint
OPTIONAL. URL of the OP's Federation specific Dynamic Client Registration Endpoint. If the OP supports explicit client registration as described in explicit registration, then this claim is REQUIRED.

3.3. OpenID Connect Discovery

The metadata type identifier is openid_discovery.

3.4. OAuth Authorization Server

The metadata type identifier is oauth_service.

All parameters defined in section 2 of RFC 8414

3.5. OAuth Client

The metadata type identifier is oauth_client.

All parameters defined in section 2 of RFC 7591

3.6. OAuth Protected Resources

The metadata type identifier is oauth_resource.

3.7. Federation Entity

The metadata type identifier is federation_entity.

Intermediates in a trust chain are of this type

Note that the information carried here is not bound to any specific protocol but of a general nature.

The following properties are allowed:

name
OPTIONAL. String. The human readable name describing the subject entity. This may be, for example, the name of an organization.
contacts
OPTIONAL. JSON array with one or more strings. Contact persons at the entity.
policy_url
OPTIONAL. URL to documentation of conditions and policies relevant to this entity
homepage_url
OPTIONAL. URL to a generic home page representing this entity.

4. Applying policy to metadata

The metadata for a specific entity can be constructed by starting with the information in leaf entity's entity statement and then applying the polices defined by the trust anchor and possible intermediates starting with the trust anchor.

4.1. Policy language

Policies are expressed using a JSON object.

There are a number of keywords defined that represents different actions/checks that MUST be applied to the metadata.

  "response_types": {
    "subset_of": ["code", "code token", "code id_token"]}
  "response_types": ["code", "code id_token token", "code id_token"]
  "response_types": ["code", "code id_token"]
  "request_object_signing_alg": {
    "one_of": ["ES256", "ES384", "ES512"]}
  "request_object_signing_alg": "ES384"
  "request_object_signing_alg": "ES384"
  "contacts": {
    "add": "support@federation.example.com"}
  "contacts": "support@org.example.com"
  "contacts": ["support@org.example.com",
               "support@federation.example.com"]
  "require_auth_time": {
    "value": true}
  "require_auth_time": true
              
  "require_auth_time": {
    "default": true }
  "require_auth_time": false
  "require_auth_time": false
              
  "require_auth_time": true
              
  "op_policy_uri": {
    "regexp": "^https:\/\/[\w-]+\.example\.com\/[\w-]+\.html"
  "op_policy_uri": "https://foo.example.com/policy.html"
              
  "op_policy_uri": "https://foo.example.com/policy.html"
              
  "tos_uri": {
    "essential": true}

These keywords are:

subset_of

The resulting value of the claim will be the intersection of the values specified here and the values of the claim. For instance, the Claim policy:
one_of

The value of the claim MUST be one of the ones listed here. As an example, if the Claim policy:
add

Disregarding what value the claim had, the value specified here will be added to the claim in the metadata statement. As an example, if the Claim policy:
value

Disregarding what value the claim had, if any, the claims value will be set to what is specified here. As an example, if the Claim policy:
default

If no value is assigned to this claim then the claims value will be set to what is specified here. As an example, if the Claim policy: require_auth_time claim then the following claim statement would be added to the metadata statement:
regexp

Matches the claim value against a regular expression. If the value does not match it will be removed. The variant of regular expression used is POSIX BRE. As an example, if the Claim policy:
essential

If 'true' then claim MUST have a value. *essential* can be combined with all the other types.

4.2. Policy Type Combinations

Some policy types can be combined with others.

default

Can be combined with *one_of*, *reg_exp* and *subset_of*.
essential

Can be combined with all the others. If essential is not present that is the same as stating essential=true.

4.3. Combining Policies

If there are more then one metadata policy in a trust chain then the policies MUST be combined before they are applied to the metadata statement.

Using the notation we have previously defined metadata policies are combined starting with ES[i] and then adding the policies from ES[j] j=i-1,..,1 before applying the combined policy to the entity's metadata

These are the policy types that can be combined when combining 2 policies:

set_of

The result of combining 2 *set_of* policies is the intersection of the values.
one_of

The result of combining 2 *one_of* policies is the intersection of the values.
add

The result of combining 2 *add* policies is the union of the values.

All the other policy types can NOT be combined. Which means that whatever a superior specifies are what goes.

4.3.1. Polciy combination example

A federations policy for RPs

{
  "scopes": {
    "subset_of": ["openid", "eduperson", "phone"],
    "default": ["openid", "eduperson"]},
  "id_token_signed_response_alg": {
    "one_of": ["ES256", "ES384", "ES512"],
    "default": "ES256"},
  "contacts: {
    "add": "helpdesk@federation.example.org"},
   "application_type": {
    "value": "web"}
}
              

An organisations policy for RPs

{
  "scopes": {
    "subset_of": ["openid", "eduperson", "address"],
    "default": ["openid", "eduperson"]},
  "id_token_signed_response_alg": {
    "one_of": ["ES256", "ES384"],
    "default": "ES256"},
  "contacts: {
    "add": "helpdesk@org.example.org"},
  "application_type": {
    "one_of": ["web", "native"]}
}
              
{
  "scopes": {
    "subset_of": ["openid", "eduperson"],
    "default": ["openid", "eduperson"]},
  "id_token_signed_response_alg": {
    "one_of": ["ES256", "ES384"],
    "default": "ES256"},
  "contacts: {
    "add": ["helpdesk@federation.example.org"],
            "helpdesk@org.example.org"]},
  "application_type": {
    "value": "web"}
}
              

If after combining a *default* value for a claim policy is not a subset of a subset_of or an one_of defined for that claim, then an error MUST be raised and the trust chain NOT used.

4.4. Enforcing Policy

If applying a policy to a metadata statement results in some claims having all their values removed and it is essential that a claim has a value then such a metadata statement MUST be regraded as broken and MUST NOT be used.

4.5. Extending the policy language

There might be parties that wants to extend the policy language defined here. If that happens then the rule is that if software compliant with this specification encounters a key word it doesn't understand it MUST refuse to apply the policy.

4.6. Policy example

The following is a non-normative example of a set of policies being applied to an RP's metadata.

The RP's metadata

{
  "contacts": ["rp_admins@cs.example.com"],
  "redirect_uris": ["https://cs.example.com/rp1"],
  "response_types: ["code"]
}            

The federations policy for RPs

{
  "scopes": {
    "subset_of": ["openid", "eduperson"]},
  "response_types": {
    "subset_of": ["code", "code id_token"]}
}
            

The organisations policy for RPs

{
  "contacts": {
    "add": "helpdesk@example.com"},
  "logo_uri": {
    "one_of": ["https://example.com/logo_small.jpg",
               "https://example.com/logo_big.jpg"],
    "default": "https://example.com/logo_small.jpg"
  },
  "policy_uri": {
    "value": "https://example.com/policy.html"},
  "tos_uri": {
    "value": "https://example.com/tos.html"}
}
            
{
  "contacts": ["rp_admins@cs.example.com", "helpdesk@example.com"],
  "logo_uri": "https://example.com/logo_small.jpg",
  "policy_uri": "https://example.com/policy.html",
  "tos_uri": "https://example.com/tos.html"
  "rp_scopes": ["openid", "eduperson"],
  "response_types": ["code"],
  "redirect_uris": ["https://cs.example.com/rp1"],
}

5. The Federation API

All entities that are expected to publish entity statements about themselves or other entities, MUST expose a Federation API endpoint.

The federation API endpoint of an entity is resolved from the entity identifier. The Federation API endpoint is found using the Well known URIs specification, with the suffix openid-federation. The scheme, host and port is taken directly from the entity identifier combined with the following path: /.well-known/openid-federation.

*Note* that since the path component of a entity ID is not included when constructing the URL above, one API endpoint may serve as the federation API endpoint for several entities.

The Federation API is an HTTPS API that may support multiple operations. Fetching entity statements is one of the operations, and the only one that all Federation API endpoints are REQUIRED to support. All the other operations are OPTIONAL. The list of defined operations may be extended in a future.

While all operations in the specification make use of a GET request, other operations may choose to use other HTTP methods. If the op parameter is left out, it is considered to be a fetch entity statements request. Unless otherwise mentioned or agreed upon, requests to the federation API does not need to be authenticated.

5.1. Fetching Entity Statement (REQUIRED)

Fetching entity statement is used to collect entity statements one by one in order to gather trust chains.

In order to fetch an entity statement, an entity needs to know the identifier of the entity to ask (the issuer), and the identifier of the entity that you want the statement to be about (the subject).

5.1.1. Fetch Entity Statements Request

The request MUST be an HTTP request using the GET method and the https scheme to a resolved federation API endpoint with the following query string parameters:

op
OPTIONAL. If not present MUST be treated as fetch.
iss
REQUIRED. The entity identifier of the issuer from which you want an entity statement issued. Because of the normalization of the URL, multiple issuers may resolve to a shared federation API. This parameter makes it explicit exactly which issuer we want entity statements from.
sub
OPTIONAL. The entity identifier of the subject for which you would like an entity statement issued. If this parameter is left out, it is considered to be the same as the issuer, and would indicate a request for a self issued statement.
aud
OPTIONAL. The entity identifier of the requester. The issuing entity may choose to include this parameter to form the entity statement specifically for this target, in which the aud claim also SHOULD be present in the entity statement self.

The following is a non-normative example of an API request for an entity statement:

GET /.well-known/openid-federation?
iss=https%3A%2F%2Fopenid.sunet.se%2Ffederation HTTP/1.1
Host: openid.sunet.se

5.1.2. Fetch Entity Statements Response

A positive response is a signed entity statement where the content type MUST be set to application/jose. If it is negative response it will be a JSON object and the content type MUST be set to application/json. More about error responses below

A non-normative example of a response:

200 OK
Last-Modified: Mon, 17 Dec 2018 11:15:56 GMT
Content-Type: application/jose

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJodHRwczovL3Nlc...

(the signed JWT is truncated)

5.2. Trust Negotiation (OPTIONAL)

An entity may use the trust negotiation operation in order to fetch resolved metadata about itself as seen/trusted by a remote peer. The result may for instance tell an RP what operations, scopes and claims an OP would allow the RP to use if a specific trust anchor was used.

5.2.1. Trust Negotiation Request

The request MUST be an HTTP request using the GET method and the https scheme to a resolved federation API endpoint with the following query string parameters:

op
REQUIRED. MUST be set to resolve_metadata.
respondent
REQUIRED. The entity identifier of the entity whose metadata are requested. Because of the normalization of the URL, multiple entity identifiers may resolve to a shared federation API. This parameter makes it explicit exactly which entity is expected.
peer
REQUIRED. The entity identifier of the entity the information is requested for. This must be a leaf entity.
type
REQUIRED. The metadata type to resolve. In this document we use the metadata types listed in Metadata.
anchor
REQUIRED. The trust anchor the remote peer MUST use when resolving the metadata.

The following is a non-normative example of an API request for trust negotiation:

GET /.well-known/openid-federation?
op=resolve_metadata&
respondent=https%3A%2F%2Fopenid.sunet.se%2Ffederation&
type=openid_provider&
peer=https%3A%2F%2Fidp.umu.se%2Fopenid HTTP/1.1
Host: openid.sunet.se

5.2.2. Trust Negotiation Response

The response is a metadata statement that is the result of applying the metadata polices in the trust chain on the entity's metadata.

A non-normative example of a response:

200 OK
Last-Modified: Wed, 22 Jul 2018 19:15:56 GMT
Content-Type: application/json

{
  "organization": "University of Ume?",
  "contacts": ["legal@umu.se", "technical@umu.se"],
  "logo_uri":
    "https://www.umu.se/SRWStatic/img/umu-logo-left-neg-SE.svg",
  "policy_uri":
    "https://www.umu.se/en/about-the-website/legal-information/",
  "authorization_endpoint":
    "https://idp.umu.se/openid/authorization",
  "token_endpoint": "https://idp.umu.se/openid/token",
  "response_types_supported": ["code", "code id_token", "token"],
  "grant_types_supported": [
    "authorization_code",
    "implicit",
    "urn:ietf:params:oauth:grant-type:jwt-bearer"
  ],
  "subject_types_supported": ["pairwise"],
  "id_token_signing_alg_values_supported": ["RS256"]
}

5.3. Entity Listings (OPTIONAL)

An entity may query another entity for a list of all the entities that that entity is prepared to issue statements about.

5.3.1. Entity Listings Request

The request MUST be an HTTP request using the GET method and the https scheme to a resolved federation API endpoint with the following query string parameters:

op
REQUIRED. MUST be set to listing.
iss
REQUIRED. The entity identifier of the entity from which an entity listing is requested. Because of the normalization of the URL, multiple entity identifiers may resolve to a shared federation API. This parameter makes it explicit exactly which entity is expected.
type
OPTIONAL. Provide this parameter to filter the results to entity statements that contain entries for this specific metadata type.
sub_is_leaf
OPTIONAL. If left out, result should include both leaf entities and intermediate nodes. If set to true, the response should contain only leaf entities. If set to false, the response should contain only intermediate nodes.
metadata_claims
OPTIONAL. A comma separated list of claim names that the requester would like to get values for for each entity. If left out or an empty string, the response should contain an empty object for each of the known entities. The set of claim names that can be used are defined in metadata. *Note* that while type and sub_is_leaf can be used to filter out which entities to return this only affects what is returned about each returned entity.

The following is a non-normative example of an API request for trust negotiation:

GET /.well-known/openid-federation?
op=listing&
iss=https%3A%2F%2Fopenid.sunet.se%2Ffederation&
type=openid_client&
metadata_claims=client_name HTTP/1.1
Host: openid.sunet.se

5.3.2. Entity Listing Response

The response MUST contain an JSON object where the known entity identifiers are the property keys, and a JSON object with the requested claims is the property value. Requested claims that the responder is not able to provide should be left out.

A non-normative example of a response:

200 OK
Last-Modified: Wed, 22 Jul 2018 19:15:56 GMT
Content-Type: application/json

{
  "https://ntnu.andreas.labs.uninett.no/": {
    "client_name": "NTNU Labs"
  },
  "https://blackboard.ntnu.no/openid/callback": {
    "client_name": "Blackboard"
  },
  "https://serviceprovider.andreas.labs.uninett.no/application17": {
    "client_name": "Test application"
  }
}

5.4. Generic Error Response

If the request was malformed, or some error occurred during processing of the request, the following standardized error format should be used regardless of the operation specified.

The HTTP response code MUST be something in 400/500-range, giving an indication of the type of error. The response body MUST be a JSON object containing the claims below and the content type MUST be set to application/json.:

op
REQUIRED. Which operation was the request processed as.
error
REQUIRED. The error code.
error_description
REQUIRED. A human readable short text describing the error.

A non-normative example of an error response:

400 Bad request
Last-Modified: Wed, 22 Jul 2018 19:15:56 GMT
Content-Type: application/json

{
  "op": "fetch",
  "error": "invalid_request",
  "error_description":
    "Required request parameter [iss] was missing."
}

6. Resolving Trust Chain and Metadata

An entity (e.g., the Consumer) that wants to establish trust with a remote peer, must have the remote peer's entity identifier and a list of entity ID's of trusted trust anchors together with the public version of their signing keys. The Consumer will first have to fetch sufficient entity statements to establish at least one chain of trust from the remote peer to one or more of the configured trust anchors. After that the entity MUST validate the trust chains independently, and -- if there are multiple valid trust chains and if the application demands it -- choose one.

6.1. Fetching Entity Statements to Establish a Trust Chain

Depending on the circumstances, the Consumer may either be handed the remote peer's self-issued entity statement or it may have to fetch it by itself. If it needs to fetch it, it will use the process described in Fetch Entity Statements with both *iss* and *sub* set to the entity ID of the remote peer.

The next step is to iterate through the list of intermediates listed in authority_hints , ignoring the authority hints that end in an unknown trust anchor, requesting an entity statement about the remote peer from each of the intermediates. If the received entity statement contains an authority hint this process is repeated. This time with the *iss* set to the intermediates entity ID and the *sub* to be the *iss* of the previous query. The Consumer should never attempt to fetch entity statements it already has fetched during this process (loop prevention).

Once the Consumer has found a trust anchor it wants to use it MUST complete the trust chain by fetching the trust anchor's self-signed entity statement.

A successful operation will return one or more lists of entity statements. Each of the lists terminating in a self-signed entity statement issued by a trust anchor.

If there is no path from the remote peer to at least one of the trusted trust anchors then the list will be empty and there is no way of establishing trust in the remote peer's information. How the Consumer deals with this is out of scope for this specification.

6.2. Validating the Trust Chains

As described in The trust chain a trust chain consists of an ordered list of entity statements. So which ever way the Consumer has acquired the set of entity statements it must now verify that it is a proper trust chain using the rules laid out in that section.

To validate the chain, the following must be done:

Verifying the signature is a much more expensive operation then verifying the correctness of the statement and the timestamps. An implementer MAY therefor chose to not verify the signature until all the other checks have been done.

No information in the chain of statements should be used before the signature chain has been validated.

6.3. Choosing One of the Valid Trust Chains

If multiple valid trust chains are found, the Consumer will need to decide on which one to use.

One simple rule would be to prefer a shorter chain over a longer one.

6.4. Calculating the Lifetime of a Trust Chain

Each entity statement in a trust chain is signed and MUST have a expiration time (exp) set. The expiration time of the whole trust chain is set to the minimum value of exp within the chain.

7. Updating Metadata, Key Rollover, and Revocation

This specification allows for a smooth process of updating metadata and public keys.

As described above in lifetime calculation each trust chain has a expiration time. A consumer of metadata using this specification MUST support refreshing a trust chain when it expires. How often a consumer SHOULD re-evaluate the trust chain depends on how quickly the consumer wants to find out that something has changed in the trust chain.

7.1. Protocol Key Rollover

If a leaf entity publishes its public keys in the metadata part using *jwks* setting an expiration time on the self-signed entity statement can be used to control how often the remote party is fetching an updated version of the public key.

If a leaf entity uses *jwks_uri* the remote party will in the normal OIDC way fetch the keys anew from the *jwks_uri* URI when it discovers that the entity uses a key it has never seen before.

7.2. Key Rollover for a Trust Anchor

A trust anchor must publish a self-signed entity statement about itself. As described above in The trust chain it should be at the end of the trust chain. The trust anchor SHOULD set a reasonable expiration time on that statement, such that the consumers will re-fetch the entity statement at reasonable intervals. If the trust root wants to roll over its signing keys it would have to:

  1. Add the new keys to the *jwks* representing the trust anchors signing keys.
  2. Keep signing the entity statement using the old keys for a long enough time period to allow all subordinates to have gotten access to the new keys.
  3. Switch to signing with the new keys.
  4. After a reasonable time period remove the old keys. What is regarded as a reasonable time is dependent on the security profile and risk assessment of the trust anchor.

It has to be taken into consideration that clients may have manually configured pubic keys as part of their configuration.

7.3. Revocation

Since the consumers are expected to check the trust chain at regular, reasonably frequent times, this specification does not specify a standard revocation process. Specific federations may make a different choice and will then have to add such a process.

8. OpenID Connect Communication

This section describes how the trust framework in this specification is used to establish trust between an RP and an OP that has no explicit configuration or registration in advance.

There is two alternative approaches to establish trust between an RP and an OP, what we call implicit and explicit registration. Members of a federation or a community should agree upon which one to use. While implementations should support both methods, deployments may choose to disable the use of one of them.

8.1. Implicit Registration

The trust between the entities is established using the above described extensions in the first two steps of the communication between an RP and an OP. How the RP found the OP in the first place is out of scope for this document.

------                                       ------
|    | <--- 1) Discovery ------------------> |    |
| RP | ---- 2) Authentication request -----> | OP |
|    |                                       |    |
------                                       ------     

The client_id of the RP MUST be set identical to the RP entity identifier.

Without a registration process, the RP does not have a client_secret. Instead the implicit registration model requires the RP to make use of asymmetric cryptography.

The RP MUST host a Federation API that allows the OP to fetch the entity statements.

8.1.1. The Authentication Request

The authentication request as specified in OpenID Connect Core.

The RP MUST authenticate at the authentication endpoint using the private_key_jwt method described in the client authentication section of OIDC core.

An authorization request example

GET /authorization?
  redirect_uri=https%3A%2F%2Fexample.com%2Fauthz_cb
  &scope=openid+profile+email+address+phone
  &response_type=code
  &nonce=4LX0mFMxdBjkGmtx7a8WIOnB&state=JpRTpu9eGXiP4thsK ...
  &state=YmX8PM9I7WbNoMnnieKKBiptVW0sP2OZ
  &client_id=https%3A%2F%2Flocalhost%3A8090%2Firp
  &client_assertion=eyJhbGciOiJSUzI1NiIs ... qx7xHcvPOdIhnpg
  &client_assertion_type=
    urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer
  HTTP/1.1
Host: https://example.org
            

8.1.2. Processing the Authentication Request

When the OP receives an incoming authentication request, the OP supports OpenID Connect Federation and the incoming client_id is a valid URL, the OP should try to resolve and fetch trust chains starting with the RP's entity statement as described in fetching entity statements.

The OP should validate the possible trust chains, as described in Trust chain validation and resolve the RP metadata with type openid_client.

The OP should consider the resolved metadata of the RP, and verify that it complies with the client metadata specification in OpenID Connect Dynamic Client Registration 1.0.

Once the OP has the RP's metadata it can verify the clients authentication.

8.1.3. Authentication Error Response

If the OP fails to establish trust with the RP, it should use the invalid_request error code, and an error_description that aids the RP to understand what is wrong.

8.2. Explicit Registration

This method involves performing an explicit registration of a new client the first time a RP interacts with an OP using something that basically follows the steps in OpenID Connect Dynamic Client Registration 1.0 but where the client registration request is a signed entity statement.

8.2.1. Provider Discovery

The RP will start by gathering the OPs metadata using the process specified in Resolving Trust Chains and Metadata above.

8.2.2. Client Registration

8.2.2.1. Client Registration Request

The OP MUST support dynamic client registration. That it does so is signaled by having the claim federation_registration_endpoint in the metadata.

Given that the OP supports dynamic registration the RP progresses as follows:

  1. Once it has the list of acceptable trust chains for the OP it MUST choose the subset it wants to progress with. The subset can be as small as one trust chain but it can also contain more than one.
  2. Based on the trust anchors referenced in the subset of trust chains, the RP will choose a set of authority_hints from its own set that terminates in those trust anchors.
  3. The RP will now construct a self-signed entity statement where the metadata statement chosen is influenced by the OPs metadata and the authority_hints included are picked by the process described above.
  4. The entity statement is sent to the federation_registration_endpoint defined in this document.

8.2.2.2. Client Registration Response

8.2.2.2.1. The OP Constructing Response

  1. After the OP receives the request, it collects and evaluates the trust chains starting with the authority_hints in the registration request. After it has verified at least one trust chain it can verify that the signature on the received registration request is correct.
  2. If it finds more then one acceptable trust chain it MUST chose one trust anchor from those chains as the one it will proceed with.
  3. At this point, if there already exists a client registration under the same entity_id then that registration MUST be regarded as invalid. *Note* that key material from the previous registration MUST be kept to make key rollover possible.
  4. The OP will now construct an metadata policy that if applied to the RP's metadata statement will result in metadata that the OP finds acceptable. *Note* that the client_id the OP chooses does not have to be the same as the entity_id of the RP. To the entity statement it will add one or more authority_hints, from its collection, that terminate in the trust anchor chosen above.
  5. It will sign and return the registration response (a signed entity statement) to the RP.

8.2.2.2.2. The RP Parsing the Response

  1. The RP verifies the correctness of the received entity statement, making sure that the trust chains starting at the authority_hints terminates in trust anchors that were referenced in the entity statement it sent to the OP.
  2. The RP MUST NOT apply metadata policies from the trust chains that the OP provides because those are not valid for the RPs metadata. The RP MUST apply policies to the metadata using one of its own trust chains that ends in the trust anchor that the OP chose. Once it has applied those policies it can the apply the policy returned from the OP. When it has applied all the metadata policies to its metadata statement, it then stores the result and can continue communicating with the OP using the agreed on metadata.
  3. At this point the RP also knows which trust chain it should use when evaluating the OPs metadata. It can therefore apply the metadata policies on the OPs metadata using the relevant trust chain and store the result as the OPs metadata.
  4. If the RP was not OK, for some reason, with the received entity statement then it has the choice to restart the registration process or to give up.

8.2.3. After client registration

A client registration using this specification is not expected to be valid forever. The entity statements exchanged all have expiration times, which means that the registration will eventually time out. An OP can also for administrative reasons decide that a client registration is not valid anymore. An example of this could be that the OP leaves the federation in use.

8.2.3.1. What the RP MUST Do

At regular intervals the RP MUST:

  1. Starting with the OPs entity statement, resolve and verify the trust chains it chooses to use when constructing the registration request. If those trust chains do not exist anymore or do not verify, then the registration should be regarded as invalid and a new registration process should be started.
  2. If the OPs entity statement was properly formed the RP must now verify that the entity statement it received about itself from the OP is still valid. Again, if that is not the case the registration should be regarded as invalid and a new registration process should be started.

What is regarded as reasonable intervals will depend on federation policies and risk assessment by the maintainer of the RP.

8.2.3.2. What the OP MUST Do

At regular intervals the OP MUST:

  1. If the signature on the registration request has expired it MUST mark the registration as invalid and demand that the RP MUST re-register. Else
  2. starting with the RPs client registration request, the OP MUST verify that there still is a valid trust chain terminating in the trust anchor the OP chose during the registration process.

8.2.4. Expiration Times

An OP MUST NOT assign a expiration time to a RP's registration that is later then the trust chains expiration time.

9. Acknowledgements

10. IANA Considerations

TBD

11. Security Considerations

TBD

12. Normative References

[OpenID.Core] Sakimura, N., Bradley, J., Jones, M., de Medeiros, B. and C. Mortimore, "OpenID Connect Discovery 1.0", August 2015.
[OpenID.Discovery] Sakimura, N., Bradley, J., Jones, M. and E. Jay, "OpenID Connect Discovery 1.0", August 2015.
[OpenID.Registration] Sakimura, N., Bradley, J. and M. Jones, "OpenID Connect Dynamic Client Registration 1.0", August 2015.
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997.
[RFC3339] Klyne, G. and C. Newman, "Date and Time on the Internet: Timestamps", RFC 3339, DOI 10.17487/RFC3339, July 2002.
[RFC5785] Nottingham, M. and E. Hammer-Lahav, "Defining Well-Known Uniform Resource Identifiers (URIs)", RFC 5785, DOI 10.17487/RFC5785, April 2010.
[RFC6749] Hardt, D., "The OAuth 2.0 Authorization Framework", RFC 6749, DOI 10.17487/RFC6749, October 2012.
[RFC7515] Jones, M., Bradley, J. and N. Sakimura, "JSON Web Signature (JWS)", RFC 7515, DOI 10.17487/RFC7515, May 2015.
[RFC7517] Jones, M., "JSON Web Key (JWK)", RFC 7517, DOI 10.17487/RFC7517, May 2015.
[RFC7591] Richer, J., Jones, M., Bradley, J., Machulak, M. and P. Hunt, "OAuth 2.0 Dynamic Client Registration Protocol", RFC 7591, DOI 10.17487/RFC7591, July 2015.
[RFC8414] Jones, M., Sakimura, N. and J. Bradley, "OAuth 2.0 Authorization Server Metadata", RFC 8414, DOI 10.17487/RFC8414, June 2018.

Appendix A. Illustrative Example of OpenID Connect Flow Using Implicit Client Registration

A service Foodle would like to offer its services to all OPs in eduGAIN. Foodle is managed and registered by the university NTNU. NTNU is part of the Norwegian Feide federation. Foodle is also directly trusted in the Swedish SWAMID federation. Both Feide and SWAMID are part of the international eduGAIN federation.

A.1. Initial Setup of Foodle

The Foodle service chooses to use the entity identifier https://foodl.org/. And upon deployment, Foodle is setup with an RSA key pair, with the following public key:

{
  "kid": "key1",
  "use": "sig",
  "kty": "RSA",
  "alg": "RS256",
  "n": "pnXBOusEANuug6ewezb9J_XbxbSGEISyA75wBGkerPNg6WTXmmxJ-DV1U4sCu
RqhSdo3Uncmw6-01bZKCtAyRHT_TOZN2TMfNPRsfLkOstVofyfxg5oIWViLX9IDG_iZVd
q6_T6yOuufOIvqpaeBMwSKuDXHNa_DU0aUu_3kOAc5_2hD4Dq-XXtum-oix2EPkNSbFfP
qFIp5n4gS1XrzGzuNQiDw82k-H6mWN0wlVWfqLxJA9DZikAX7x9feipn36wxDH-XUlzDD
Ui3nfnC8GSkT-CYII3oZPsIgMV527iQGVsehIV9KqTF2FnaP83cqV9YgvMfhs1wrx4L3Z
-3B8Q",
  "e": "AQAB",
  "key_ops": ["verify"],
  "ext": true
}

Foodle offers a WebFinger interface and a metadata API according to this specification, with the ability to issue entity statements about itself.

A.2. Federation Setup

How trust is established and entities becomes part of a federation is out of scope of this specification. It could involve some kind of non-technical contract, agreement or term of use that is established, followed by a federation or trust issuer that registers an entity identifier, public key and a set of metadata that restricts the delegated trust that is represented in the entity statement about the joining party.

The following example, assumes the following trust relations are established, and the following entities are able to issue entity statements:

Foodle has a local trust root configuration that contains public signing keys for known federations:

"https://www.sunet.se/swamid"

[
{
  "keys": [
    {
      "kty": "RSA",
      "alg": "RS256",
      "n": "v6xydqciFKGfvQaqYGmk9A7etbfvNY[...]",
      "e": "AQAB",
      "key_ops": ["verify"],
      "ext": true,
      "kid": "swamid",
      "use": "sig"
    }
  ]
}
]

A.3. User Chooses to Login at Foodle

Let us assume a student from Umeå would like to login at Foodle. Some sort of discovery process involves the end user choosing an OPs. OpenID Discovery using the e-mail address is one option. Foodle presenting a list of available OPs for the user to choose from is another.

After the discovery process, Foodle knows that the user would like to login using the OP with entity identifier https://www.umu.se/openid.

A.4. Foodle Discovers the OP

Foodle normalizes the entity identifier of the OP, and performs a request to fetch the self-issued entity statement using the Federation API of the OP.

GET /.well-known/openid-federation?
iss=https%3A%2F%2Fumu.se%2Fopenid HTTP/1.1
Host: umu.se
HTTP/1.1 200 OK
Content-Type: application/json
["eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InVtdSJ9.eyJpYXQi..."]

The API endpoint returns a list of signed entity statements. In this case we look for a self-issued statement from the Umeå university. We then decode and inspect the content:

{
  "iat": 1539174048,
  "exp": 1539177648,
  "metadata": {
    "openid_provider": {
      "authorization_endpoint":
        "https://idp.umu.se/openid/authorization",
      "token_endpoint": "https://idp.umu.se/openid/token",
      "response_types_supported": ["code", "code id_token", "token"],
      "grant_types_supported": [
        "authorization_code",
        "implicit",
        "urn:ietf:params:oauth:grant-type:jwt-bearer"
      ],
      "subject_types_supported": ["pairwise", "public"],
      "id_token_signing_alg_values_supported": ["RS256"],
      "logo_uri":
        "https://www.umu.se/img/umu-logo-left-neg-SE.svg",
      "policy_uri":
        "https://www.umu.se/en/website/legal-information/",
      "loa_max": "http://eidas.europa.eu/LoA/high"
    }
  },
  "iss": "https://umu.se/openid",
  "sub": "https://umu.se/openid",
  "authority_hints": {
    "https://www.sunet.se/swamid": ["https://edugain.org/oidc"],
    "https://kalmar2.org/openid": []
  },
  "jwks": {
    "keys": [
      {
        "kty": "RSA",
        "alg": "RS256",
        "n": "z1V1kyi6qwmXfKsfhVqKUMmQH3AixN[...]",
        "e": "AQAB",
        "key_ops": ["verify"],
        "ext": true,
        "kid": "umu",
        "use": "sig"
      }
    ]
  }
}

A.5. Resolving the OP's Trust Chain

In order to establish trust with this OP, the Foodle RP would need to fetch sufficient entity statements to represent a complete chain from the self-issued statement to the locally configured trust root, which contains SWAMID.

The information found in the authority_hints is critical in order to dynamically discover the trust chain. If such hints are not present, the RP may resume to fixed configured trust roots to ask for entity statements.

In this example, Foodle now fetches an entity statement from SWAMID using the Federation API endpoint of SWAMID, discovered in the authority_hints claim.

GET /.well-known/openid-federation?
iss=https%3A%2F%2Fwww.sunet.se%2Fswamid&
sub=https%3A%2F%2Fumu.se%2Fopenid HTTP/1.1
Host: www.sunet.se
HTTP/1.1 200 OK
Content-Type: application/json
["eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImZlaWRlIn0.eyJpY..."]

The decoded version of the entity statement is:

{
  "iat": 1539174048,
  "exp": 1539177648,
  "metadata_policy": {
    "openid_provider": {
      "subject_types_supported": {
        "value": ["pairwise"]},
      "id_token_signing_alg_values_supported":{
          "subset_of": ["RS256", "RS512"],
          "default: ["RS256", "RS512"]
        }
      "organization": {
        "value": "University of Ume&aring;"},
      "contacts": {
        "add": ["legal@umu.se", "technical@umu.se"]}
    },
    "openid_client": {},
  },
  "iss": "https://www.sunet.se/swamid",
  "sub": "https://umu.se/openid",
  "jwks": {
    "keys": [
      {
        "kty": "RSA",
        "alg": "RS256",
        "n": "v6xydqciFKGfvQaqYGmk9A7etbfvNY[...]",
        "e": "AQAB",
        "key_ops": ["verify"],
        "ext": true,
        "kid": "swamid",
        "use": "sig"
      }
    ]
  }
}

Notice that the entity statement about University of Umeå also contains an entry for openid_client metadata. This indicates that SWAMID expresses this university to be trusted to issue its own OpenID clients without the need for registering these directly in SWAMID.

These two entity statements are sufficient to establish a path from the local configured trust anchor which trust SWAMID, to the self-issued statement from the University of Umeå. Here are the steps performed to validate the trust chain:

A.6. Extracting the OP metadata

The output from the trust chain validation is an ordered list of entity statements. In order to extract the needed metadata, we need to look at the metadata type relevant in the given context. In this case, we are establishing trust with an OP, and we take the openid_provider metadata object from the entity statement published by the OP and the policy statements from the other entities in the trust chain:

SWAMID's metadata policy for an openid_provider

[
{"loa_max":
  {"value":"http://swamid.se/LoA/substantial"}}
]

UMU's metadata policy for an openid_provider

[
{
  "subject_types_supported": {"value": ["pairwise"]},
  "id_token_signing_alg_values_supported":
    {
      "subset_of": ["RS256", "RS512"],
      "default: ["RS256", "RS512"]
    }
  "organization": {"value": "University of Ume&aring;"},
  "contacts": {"add": ["legal@umu.se", "technical@umu.se"]}
}
]

The OP's metadata statement

[
{
  "authorization_endpoint":
    "https://idp.umu.se/openid/authorization",
  "token_endpoint": "https://idp.umu.se/openid/token",
  "response_types_supported": ["code", "code id_token", "token"],
  "grant_types_supported": [
    "authorization_code",
    "implicit",
    "urn:ietf:params:oauth:grant-type:jwt-bearer"
  ],
  "subject_types_supported": ["pairwise", "public"],
  "id_token_signing_alg_values_supported": ["RS256"],
  "logo_uri":
      "https://www.umu.se/SRWStatic/img/umu-logo-left-neg-SE.svg",
  "policy_uri":
      "https://www.umu.se/en/about-the-website/legal-information/",
  "loa_max": "http://eidas.europa.eu/LoA/high"
}
]

Applying the metadata policies to the metadata produces the following result:

{
  "organization": "University of Ume&aring;",
  "contacts": ["legal@umu.se", "technical@umu.se"],
  "logo_uri":
    "https://www.umu.se/SRWStatic/img/umu-logo-left-neg-SE.svg",
  "policy_uri":
    "https://www.umu.se/en/about-the-website/legal-information/",
  "authorization_endpoint":
    "https://idp.umu.se/openid/authorization",
  "token_endpoint": "https://idp.umu.se/openid/token",
  "response_types_supported": ["code", "code id_token", "token"],
  "grant_types_supported": [
    "authorization_code",
    "implicit",
    "urn:ietf:params:oauth:grant-type:jwt-bearer"
  ],
  "subject_types_supported": ["pairwise"],
  "id_token_signing_alg_values_supported": ["RS256"],
  "loa_max": "http://swamid.se/LoA/substantial"
}

A.7. RP Sends Authentication Request (Implicit Registration)

Foodle after establishing trust with the University of Umeå and extracted metadata and a set of metadata policies, will send an authentication request to the OP. This example involves the implicit registration.

GET /authorize?
  response_type=code
  &scope=openid%20profile%20email
  &client_id=https%3A%2F%2Ffoodl.org%2F
  &state=2ff7e589-3848-46da-a3d2-949e1235e671
  &redirect_uri=https%3A%2F%2Ffoodl.org%2Fopenid%2Fcallback
  &client_assertion=eyJhbGciOiJSUzI1NiIs ... qx7xHcvPOdIhnpg
  &client_assertion_type=
    urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer
  HTTP/1.1
Host: idp.umu.se

Here is an example of an authentication request:

The OP receiving this authentication request will, unless the RP is cached or statically configured, start to dynamically fetch and establish trust with the RP.

A.8. OP Fetches Entity Statements

The OP needs to establish a trust chain for the RP from which a authentication was received. The OP in this example are configured with public key of 2 federations:

"https://edugain.org/oidc"

[
 {
  "keys": [
    {
      "kty": "RSA",
      "use": "sig",
      "alg": "RS256",
      "n": "qnd5_krrHKzuJzb5_YEt4sP-YOGSbf[...]",
      "e": "AQAB",
      "key_ops": ["verify"],
      "ext": true,
      "kid": "edugain"
    }
  ]
}
        

"https://www.sunet.se/swamid"

[
{
  "keys": [
    {
      "kty": "RSA",
      "alg": "RS256",
      "n": "v6xydqciFKGfvQaqYGmk9A7etbfvNY[...]",
      "e": "AQAB",
      "key_ops": ["verify"],
      "ext": true,
      "kid": "swamid",
      "use": "sig"
    }
  ]
}
        

A.9. RP Fetches Entity Statements

The RP starts to resolve metadata for the client identifier https://foodl.org/ by fetching the self-issued entity statement using the Federation API.

uses WebFinger, the metadata API endpoints and the authority_hints in order to establish a full trust chain to the trust root.

In this case there are two possible trust chains:

Appendix B. Illustrative Example of OpenID Connect Flow Using Explicit Client Registration

A research project has pooled resources and bought an extremely rare and expensive equipment (EREE) that MUST be accessible by all project participants disregarding which university/research organization/company they belong for. To that end the research project have created its own federation (EREE) and are expecting the participants to get their organizations OP to register with the EREE federation. These OPs are of course expected to be members in one or more other federations. So we have to EREE service and an EREE federation. Since the EREE equipment is placed in Sweden the EREE service is also member of the SWAMID federation.

B.1. Initial Setup of the EREE Service

The EREE service choose to use the entity identifier https://srv.eree.example.org/. And upon deployment, EREE is setup with a Elliptic Curve key pair, with the following public key:

{
  "keys": [
    {
      "kty": "EC",
      "use": "sig",
      "kid":
        "bmRkVmk0QUY3UUdnM3NDekI4VGptRUIxVk5lRXIyVE9rRUZpMUpNbGJ...",
      "crv": "P-256",
      "x": "ypFDCBLLT7lRP8UPo12ycnIkyFjeL1yco_Iu7VZoeDk",
      "y": "1sO4UIY1Iil0_PYobPKhuhs5ocQqVWYCujXcfo47epg"
    }
  ]
}

              
{"https://eree.example.org":["https://eree.example.org"]

            

The EPEE service is provided files containing authority_hints by its superiors. From the EPEE federation it gets:

              
{"https://swamid.se":["https://swamid.se"]

            

from SWAMID:

              
{"https://uninett.no":["https://uninett.no"]

            

and from UNINETT:

and so on

On the federations side:

And finally, from the federations the EPEE service also receives the public part of the federations signing keys.

B.2. Researcher Wants to Start a Job at the EPEE Service

A researcher from Umeå wants to access the EPEE service. The EPEE service provides a discovery service which allows the researcher to chose which OP to use. In this case https://op.umu.se/ .

B.3. The EPEE RP Discovers and Initiates Explicit Registration

B.3.1. The EPEE RP Discovers the OpenID Provider

Using the entity ID (issuer ID) of the OP the service performs a fetch entity statement request as described in Fetch Entity Statement

                
 GET
 /.well-known/openid-federation?iss=https%3A%2F%2Fop.umu.se
 HTTP/1.1
 Host: op.umu.se
              
              

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

eyJhbGciOiJFUzI1NiIsImtpZCI6IlFVOUxUbkpzTjJ4VVRYQkZSM040T1Z...
              
              

                
{
  "authority_hints": {
    "https://epee.example.org": [
      "https://epee.example.org"
    ],
    "https://swamid.se": [
      "https://swamid.se"
    ]
  },
  "exp": 1543851936,
  "iat": 1543247136,
  "iss": "https://op.umu.se",
  "jwks": {
    "keys": [
      {
        "crv": "P-256",
        "kid":
          "QU9LTnJsN2xUTXBFR3N4OVZOeTlyejFrWWthYWlaTllYMDR...",
        "kty": "EC",
        "use": "sig",
        "x": "DU6e1SjvW3Gqcd7up-n8s1N6Zlm2cNlZjYqL3O36v1A",
        "y": "pEtk0_fSKN56V-2hDnzFUbaw8-v0QBjNoT2KaZ7pqIc"
      }
    ]
  },
  "metadata": {
    "openid_provider": {
      "authorization_endpoint":
        "https://op.umu.se/authorization",
      "federation_registration_endpoint":
        "https://op.umu.se/fedreg",
      "grant_types_supported": [
        "authorization_code",
        "implicit",
        "urn:ietf:params:oauth:grant-type:jwt-bearer"
      ],
      "id_token_signing_alg_values_supported": [
        "RS256"
      ],
      "logo_uri":
        "https://www.umu.se/img/umu-logo-left-neg-SE.svg",
      "policy_uri":
        "https://www.umu.se/en/website/legal-information/",
      "response_types_supported": [
        "code",
        "code id_token",
        "token"
      ],
      "subject_types_supported": [
        "pairwise",
        "public"
      ],
      "token_endpoint": "https://op.umu.se/token",
      "userinfo_endpoint": "https://op.umu.se/user"
    }
  },
  "sub": "https://op.umu.se"
}
                
              

The decoded version of the entity statement is:

B.3.2. Resolving the OP's Trust Chain

In order to establish trust with this OP, the EEPE service provider would need to fetch sufficient entity statements to represent a complete chain from the self issued statement to the trust anchor that represents the EPEE federations.

                
GET
/.well-known/openid-federation?
iss=https%3A%2F%2Feree.example.org&
sub=https%3A%2F%2Fop.umu.se HTTP/1.1
Host: eree.example.org
              
              

The authority_hints in the self-signed entity statement points to 2 trust anchors "https://epee.example.org" and "https://swamid.se" of these only the *EPEE* one is interesting. The RP therefor chooses to only follow that trust path. The next step being fetching an entity statement about "https://op.umu.se" signed by the EPEE federation. This is done by doing a fetch entity statement:

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

eyJhbGciOiJFUzI1NiIsImtpZCI6IlFuRlJWMEZ6YjE5NVdW...
              
              

                
{
  "exp": 1543852816,
  "iat": 1543248016,
  "iss": "https://eree.example.org/",
  "jwks": {
    "keys": [
      {
        "crv": "P-256",
        "kid":
        "QU9LTnJsN2xUTXBFR3N4OVZOeTlyejFrWWthYWlaTllYMDRXSk",
        "kty": "EC",
        "use": "sig",
        "x": "DU6e1SjvW3Gqcd7up-n8s1N6Zlm2cNlZjYqL3O36v1A",
        "y": "pEtk0_fSKN56V-2hDnzFUbaw8-v0QBjNoT2KaZ7pqIc"
      }
    ]
  },
  "metadata": {
    "openid_provider": {}
  },
  "sub": "https://op.umu.se",
  "sub_is_leaf": true
}
              
              

The decoded version of the returned entity statement is:

A couple of things worth noting about the response:

B.3.3. Validating the Trust Chain

These two entity statements are sufficient to establish a path from the local configured trust anchor which trust the EPEE federation, to the self-issued statement from the OP at the University of Umeå. Here are the steps performed to validate the trust chain as described in validating the trust chain. We start with the signed entity statement issued by EPEE about the OP at the University of Umeå

  1. Verify that the *sub* in the entity statement is the OPs entity ID.
  2. Find the trusted public keys for the EPEE federation in the local trust configuration.
  3. Use these keys to validate the signature of the signed entity statement. Provided that works out OK
  4. Extract the jwks from the entity statement and convert it to a set of keys

Now, we can work on the self-signed entity statement published by the OP@UmU.

  1. Verify that the *sub* and the *iss* in the entity statement is the OPs entity ID.
  2. Using the keys extracted above, verify the signature of the signed entity statement

B.3.4. Extracting the OP's Metadata

The output from the trust chain validation is an ordered list of entity statements. In order to extract the needed metadata, we need to look at the metadata type relevant in the given context. In this case, we are establishing trust with an OP, and we take a look at the *openid_provider* metadata and metadata_policy objects of the trust chain:

Metadata polices

                [
  {}
                

Metadata statement

                [

  {
    "authorization_endpoint":
    "https://op.umu.se/authorization",
    "federation_registration_endpoint":
      "https://op.umu.se/fedreg",
    "grant_types_supported": [
      "authorization_code",
      "implicit",
      "urn:ietf:params:oauth:grant-type:jwt-bearer"
    ],
    "id_token_signing_alg_values_supported": [
      "RS256"
    ],
    "logo_uri":
      "https://www.umu.se/img/umu-logo-left-neg-SE.svg",
    "policy_uri":
      "https://www.umu.se/en/website/legal-information/",
    "response_types_supported": [
      "code",
      "code id_token",
      "token"
    ],
    "subject_types_supported": [
      "pairwise",
      "public"
    ],
    "token_endpoint": "https://op.umu.se/token",
    "userinfo_endpoint": "https://op.umu.se/user"
  }

              

Since there is no metadata policy defined, the response will just be the metadata statement as it is.

B.3.5. EPEE RP Does Federated Client Registration

                
{
  "authority_hints": {
    "https://eree.example.org": [
      "https://eree.example.org"
    ]
  },
  "jwks": {
    "keys": [
      {
        "crv": "P-256",
        "kid":
          "bmRkVmk0QUY3UUdnM3NDekI4VGptRUIxVk5lRXIyVE9rRUZpMUpNb...",
        "kty": "EC",
        "use": "sig",
        "x": "ypFDCBLLT7lRP8UPo12ycnIkyFjeL1yco_Iu7VZoeDk",
        "y": "1sO4UIY1Iil0_PYobPKhuhs5ocQqVWYCujXcfo47epg"
      }
    ]
  },
  "metadata": {
    "openid_client": {
      "application_type": "web",
      "request_object_signing_alg": "ES256",
      "response_types": [
        "code"
      ],
      "scope": [
        "openid",
        "email"
      ],
      "token_endpoint_auth_method": "private_key_jwt",
      "token_endpoint_auth_signing_alg": "ES256",
      "userinfo_signed_response_alg": "ES256"
    }
  },
  "iss": "https://rp.eree.example.org",
  "sub": "https://rp.eree.example.org"
}
              
              

Now when the RP has trusted information about the OP it can do a dynamic client registration. To that end it collects information about itself that it wants to register. This should be no different from what a normal OIDC RP does. To this it adds information about the RP federation signing keys, the *sub* and *authority_hints*. Ones it has all that information it creates an entity statement. The result of all this work may look something like this:

Next it self-signs this statement and sends it as a client registration request to the *federation_registration_endpoint* of the OP.

B.4. The OP Deals With a Client Registration Request

B.4.1. The OP Gathers the RPs Trust Chains

To collect the trust chains the OP uses the *authority_hints* in the self-signed entity statement it received from the RP (the client registration request).

                
GET
/.well-known/openid-federation?
iss=https%3A%2F%2Feree.example.org&
sub=https%3A%2F%2Frp.epee.example.org HTTP/1.1
Host: eree.example.org
              
              

In this case it is only one which points to *https://eree.example.org* . So the OP fetches the entity statement that the EPEE federation publishes on the EPEE RP.

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

eyJhbGciOiJFUzI1NiIsImtpZCI6IlFuRlJWMEZ6YjE5NVd...
              
              

With the response:

                
{
  "exp": 1543865440,
  "iat": 1543260640,
  "iss": "https://eree.example.org",
  "jwks": {
    "keys": [
      {
        "crv": "P-256",
        "kid":
          "bmRkVmk0QUY3UUdnM3NDekI4VGptRUIxVk5lRXIyVE9rRUZpM...",
        "kty": "EC",
        "use": "sig",
        "x": "ypFDCBLLT7lRP8UPo12ycnIkyFjeL1yco_Iu7VZoeDk",
        "y": "1sO4UIY1Iil0_PYobPKhuhs5ocQqVWYCujXcfo47epg"
      }
    ]
  },
  "metadata": {
    "openid_client": {
      "application_type": "web",
      "request_object_signing_alg": "ES256",
      "response_types": [
        "code"
      ],
      "scope": [
        "openid",
        "email"
      ],
      "token_endpoint_auth_method": "private_key_jwt",
      "token_endpoint_auth_signing_alg": "ES256",
      "userinfo_signed_response_alg": "ES256"
    }
  },
  "sub": "https://rp.eree.example.org"
}
                
              

Unpacked this becomes:

B.4.2. Validating the Trust Chain

The process here is the one described in validating the trust chain.

B.4.3. Extracting RP Metadata

                
{
  "application_type": "web",
  "application_name": "EPEE",
  "contacts": ["ops@epee.example.org"],
  "jwks_uri": "https://rp.eree.example.org/static/jwks.json",
  "redirect_uris": [
    "https://rp.eree.example.org/authz_cb"
  ],
  "request_object_signing_alg": "ES256",
  "response_types": [
    "code"
  ],
  "scope": [
    "openid",
    "email"
  ],
  "token_endpoint_auth_method": "private_key_jwt",
  "token_endpoint_auth_signing_alg": "ES256",
  "userinfo_signed_response_alg": "ES256"
}
                
              

The OP applies the metadata policies on the leaf entity's metadata, all from the trust chain and comes up with:

B.4.4. Constructing the Registration Response

                
{
  "authority_hints": {
    "https://eree.example.org": [
      "https://eree.example.org"
    ]
  },
  "exp": 1543931097,
  "iat": 1543326297,
  "iss": "https://op.umu.se",
  "metadata_policy": {
    "openid_client": {
      "client_id": {"value": "FjeL1yco_Iu7VZoeDk"}
    }
  },
  "sub": "https://rp.eree.example.org"
}
                
              

Happy with the information in the client registration request the OP constructs its metadata policy and creates an entity statement by adding *sub* and *authority_hints*:

B.5. The RP Deals With the Registration Response

The RP MUST collect the trust chain ending in the EPEE trust anchor and verify the correctness of the trust chain but refrain from processing the metadata. This since the entity statement issued by the EPEE federation about the UmU OP are only valid for that entity and not for the EPEE RP.

If the RP is OK with what the OP decided on regarding the RPs metadata then it will store this to be used in the following OIDC protocol exchange with the OP.

In this example the RP decided on one specific trust anchor before sending the registration request. If that was not the case but the RP had chosen to send a registration request with more than one authority_hint then this by time the RP could not apply any metadata polices to the metadata statement since it would not know which to use.

Appendix C. Notices

Copyright (c) 2018 The OpenID Foundation.

The OpenID Foundation (OIDF) grants to any Contributor, developer, implementer, or other interested party a non-exclusive, royalty free, worldwide copyright license to reproduce, prepare derivative works from, distribute, perform and display, this Implementers Draft or Final Specification solely for the purposes of (i) developing specifications, and (ii) implementing Implementers Drafts and Final Specifications based on such documents, provided that attribution be made to the OIDF as the source of the material, but that such attribution does not indicate an endorsement by the OIDF.

The technology described in this specification was made available from contributions from various sources, including members of the OpenID Foundation and others. Although the OpenID Foundation has taken steps to help ensure that the technology is available for distribution, it takes no position regarding the validity or scope of any intellectual property or other rights that might be claimed to pertain to the implementation or use of the technology described in this specification or the extent to which any license under such rights might or might not be available; neither does it represent that it has made any independent effort to identify any such rights. The OpenID Foundation and the contributors to this specification make no (and hereby expressly disclaim any) warranties (express, implied, or otherwise), including implied warranties of merchantability, non-infringement, fitness for a particular purpose, or title, related to this specification, and the entire risk as to implementing this specification is assumed by the implementer. The OpenID Intellectual Property Rights policy requires contributors to offer a patent promise not to assert certain patent claims against other contributors and against implementers. The OpenID Foundation invites any interested party to bring to its attention any copyrights, patents, patent applications, or other proprietary rights that may cover technology that may be required to practice this specification.

Appendix D. Document History

[[ To be removed from the final specification ]]

-07

-06

-05

-04

Authors' Addresses

Roland Hedberg (editor) independent EMail: roland@catalogix.se
Andreas Åkre Solberg Uninett AS EMail: andreas.solberg@uninett.no URI: https://www.linkedin.com/in/andreassolberg/
Samuel Gulliksson Schibsted Media Group EMail: samuel.gulliksson@gmail.com
Michael B. Jones Microsoft EMail: mbj@microsoft.com URI: http://self-issued.info/
John Bradley Yubico EMail: ve7jtb@ve7jtb.com URI: http://www.thread-safe.com/