Skip to content
Connect2id

OpenID Federation policy guide

How to design metadata policies for protocol and API interoperability between federated entities, such as applications, services or devices? How to enforce a common security profile in a federation? This guide for federation operators explains the principles and operation of the OpenID Federation 1.0 metadata policy language and how to apply it effectively.

1. The purpose of entity metadata

When a federation is formed it is to a create a network of trust for its participants. The participants can then safely do business with one another, using one or more agreed-upon protocols. In a federation set up to authenticate users the protocol can be OpenID Connect. In a federation of verifiable credential (VC) issuers, wallets and verifiers the protocols can be based on the OIDC4VC/VP specs.

A protocol may require certain data about the other entity to be known prior to the transaction. For example, in OpenID Connect the identity provider needs to know at a minimum the redirection URI of the relying party in order to handle a login request from it.

To this end OpenID Federation 1.0 enables an entity to publish metadata about itself in its entity configuration, so that other federation participants can readily obtain it, as part of the trust chain resolution. The metadata is published under an entity type identifier, for example openid_relying_party for OpenID relying party metadata. This guarantees the type safety of metadata and enables entities to potentially have multiple distinct protocol identities.

Example metadata for an OpenID relying party:

{
  "metadata" : {
    "openid_relying_party" : {
      "redirect_uris" : [ "https://rp.example.com/cb" ],
      "client_name" : "XYZ app",
      "logo_uri" : "https://rp.example.com/logo.png",
      "signed_jwks_uri" : "https://rp.example.com/jwks.jwt",
      "token_endpoint_auth_method" : "private_key_jwt",
      "token_endpoint_auth_signing_alg" : "RS256"
    }
  }
}

Here are some commonly occurring purposes of entity metadata:

  • Enable the discovery of protocol specific endpoints. In OpenID Connect this can be the redirect_uri of the relying party, or the keys, authorisation and token endpoints of the identity provider.

  • List supported cryptography algorithms. In OpenID Connect this can include the JWS algorithm for JWT-based client authentication.

  • Configure UIs. In OpenID Connect this can be the client name and logo to display on the login screen.

  • Identify supported protocol extensions. In OpenID Connect this can be extensions such as Identity Assurance / eKYC.

2. When should metadata be policed?

When policing of the published entity metadata becomes necessary this usually boils down to these two reasons:

  • To ensure interoperability between entities at the protocol level – When the metadata contains optional parameters or must be configured in a certain way to ensure all entities can successfully interop with one another. In OpenID Connect an example of this is that both providers and relying parties must publish support for the same method(s) of client authentication. If that isn’t observed a login requests may fail due to the client using an inappropriate authentication method.

  • To enforce a security profile – When the protocol and its metadata support varying levels of security and all entities in the federation must comply with a certain profile. In OpenID Connect this could for instance be a requirement to support a FAPI security profile.

Federation designers may feel tempted to use the policy facility to enforce type checks on the JSON values of metadata parameters. This is an antipattern, federation policies should not be concerned with such checks. Tney should be done by the application layer, which receives the resolved metadata as a JSON object to parse into an internal application specific representation.

Metadata policies may not be needed when the following is true:

  • The metadata is minimal, has no optional parameters or generally doesn’t allow metadata instances with incompatible interoperability to be specified.

  • The application protocol / layer is capable on its own to enforce any interoperability or security requirements of the federation.

Future protocols that are designed for use by entities in OpenID compliant federations may be devised so that the metadata requires little or no special policies.

3. Principles of the policy language

In the previous section we learned that OpenID Federation 1.0 enables operators to define policies for metadata published by entities.

The policy language has a simple expressive syntax that is entirely JSON based. This means metadata policies can be seamlessly embedded in subordinate statements issued by trust anchors and intermediate entities. No special parsing is needed to parse the policy syntax, this can be done with the help of regular JSON libraries.

The policy language in OpenID Federation 1.0 was designed around 6 principles:

  1. Hierarchy

    Trust anchors and intermediate entities can define policies in the subordinate statements they issue. Once defined, a policy cannot be overridden, repealed or made more permissive by intermediate entities that are subordinate in the trust chain.

    The hierarchy of policies is preserved in nested multilateral federations where a trust anchor in one federation may act as an intermediate entity in another.

  2. Specificity

    Just like metadata, the policies are entity-type specific. The policies for different entity types, for example OpenID providers on one hand and OpenID relying parties on the other, are thus cleanly and reliably isolated from one another.

    When a trust anchor or an intermediate entity publishes a policy, it applies to all descendant entities in the trust chain. Because the place to define a policy is the subordinate statement, and every statement is issued for a specific subject, a federation authority can choose to define a common policy for all its subordinates (and their descendants), or specific policies for specific subordinates.

  3. Granularity

    Policies are expressed at the level of individual metadata parameters. The policies for a given metadata parameter are thus independent and isolated from those for other parameters.

  4. Operation

    A policy operates by performing a check, a modification, or a combination of both on a given metadata parameter.

    OpenID Federation 1.0 specifies 7 standard operators. A federation may define and use additional custom operators, provided they don’t break the general principles of policy.

  5. Integral metadata policing

    The resolution and application of metadata policies is an integral part of the trust chain resolution process.

    This means:

    • A trust chain with entity metadata that does not comply with the resolved policies is automatically deemed invalid.

    • A trust chain which policy resolution fails due to an error, for example due to an intermediate entity’s policy clashing with a superior’s policy, is deemed invalid too.

  6. Determinism

    The resolution and application of metadata policies in a trust chain is deterministic. This means trust anchors and intermediate entities are able to formulate policies that exhibit predictable and reproducible outcomes.

4. Operators

OpenID Federation 1.0 defines 7 operators for validating and shaping entity metadata in a trust chain.

Policy operator Purpose JSON type
Modifier Check Policy operator Metadata parameter
value v x any any
add v x any JSON array
default v x any any
essential x v true, false any
one_of x v JSON array (1) any
subset_of v v JSON array JSON array
superset_of v v JSON array JSON array

Legend:

  • “any” means any JSON value type per RFC 8259, section 3.
  • (1) the JSON array must not be empty

Policy operator: value

The value operator sets or overrides a metadata parameter.

Scenario 1

Example policy to ensure RPs will be registered to receive ID tokens with the auth_time claim, by setting the require_auth_time metadata parameter to true.

{
  "require_auth_time" : {
     "value" : true
  }
}
</tr>
<tr>
    <td>B</td>
    <td style="padding: 0">
{
  "require_auth_time" : false
}
    </td>
    <td style="padding: 0">
{
  "require_auth_time" : true
}
</tr>
Input metadata Output metadata
A
{}

{
  "require_auth_time" : true
}

Scenario 2

Example policy to ensure RPs cannot register a 3rd party login initiation URL, by removing any initiate_login_uri metadata parameter.

{
  "initiate_login_uri" : {
    "value" : null
  }
}
</tr>
<tr>
    <td rowspan="2">B</td>
    <td style="padding: 0">
{
  "initiate_login_uri" : "https://example.com/login"
}
    </td>
    <td style="padding: 0">
{}


</tr>
Input metadata Output metadata
A
{}

{}

Policy operator: add

The add operator appends one or more values to a metadata parameter of type JSON array.

Scenario 1

Example policy by an intermediate federation entity that adds the email address of its administrator to the contacts metadata parameter of subordinate RPs.

{
  "contacts" : {
    "add" : "admin@example.com"
  }
}
</tr>
Input metadata Output metadata
A
{}
{
  "contacts" : [ "admin@example.com" ]
}
B
{
  "contacts" : [ "support@example.com" ]
}

{
  "contacts" : [ "support@example.com",
                 "admin@example.com" ]
}

Scenario 2

Example policy that adds two email addresses to the contacts metadata parameter of subordinate RPs.

{
  "contacts" : {
    "add" : [ "admin@example.com", "webmaster@example.com" ]
  }
}
</tr>

<tr>
    <td>B</td>
    <td style="padding: 0">
{
  "contacts" : [ "alice@example.com" ]
}


    </td>
    <td style="padding: 0">
{
  "contacts" : [ "alice@example.com",
                 "admin@example.com",
                 "webmaster@example.com" ]
}
</tr>
Input metadata Output metadata
A
{}

{
  "contacts" : [ "admin@example.com",
                 "webmaster@example.com" ]
}

Policy operator: default

The default operator specifies a parameter when it’s absent in the metadata.

Scenario 1

Example policy that sets the ID token JWS algorithm to RS256 for RPs that don’t specify an algorithm in their metadata.

{
  "id_token_signed_response_alg" : {
    "default" : "RS256"
  }
}
</tr>
<tr>
    <td>B</td>
    <td style="padding: 0">
{
  "id_token_signed_response_alg" :
    "ES256"
}
    </td>
    <td style="padding: 0">
{
  "id_token_signed_response_alg" :
    "ES256"
}
</tr>
Input metadata Output metadata
A
{}

{
  "id_token_signed_response_alg" :
    "RS256"
}

Policy operator: essential

When true the essential operator requires a metadata parameter to be present. When false the metadata parameter is voluntary and may be absent. The essential operator has a default value false (voluntary). Entity metadata that is missing an essential parameter is considered invalid.

Scenario 1

Example policy that requires RPs to provide a client_name metadata parameter.

{
  "client_name" : {
    "essential" : true
  }
}
</tr>
Input metadata Output metadata
A
{
  "client_name" : "My Payments App"
}
{
  "client_name" : "My Payments App"
}
B
{}

INVALID METADATA

Scenario 2

Example RP policy that marks the client_name metadata parameter as voluntary. This is the same as omitting essential.

{
  "client_name" : {
    "essential" : false
  }
}
</tr>
Input metadata Output metadata
A
{
  "client_name" : "My Payments App"
}
{
  "client_name" : "My Payments App"
}
B
{}

{}

Policy operator: one_of

The one_of operator ensures a metadata parameter that is present and not null is set to a whitelisted value.

Scenario 1

Example policy to ensure that when RPs choose to register for signed UserInfo responses the JWS algorithm must be either PS256 or ES256.

{
  "userinfo_signed_response_alg" : {
    "one_of" : [ "PS256", "ES256" ]
  }
}
</tr>
<tr>
    <td>B</td>
    <td style="padding: 0">
{
  "userinfo_signed_response_alg" :
    "PS256"
}
    </td>
    <td style="padding: 0">
{
  "userinfo_signed_response_alg" :
    "PS256"
}
</tr>
<tr>
    <td>C</td>
    <td style="padding: 0">
{
  "userinfo_signed_response_alg" :
    "RS256"
}
    </td>
    <td style="padding: 0">
INVALID METADATA



</tr>
Input metadata Output metadata
A
{}

{}

Scenario 2

Example policy that requires RPs to register either for the PS256 or the ES256 ID token JWS algorithm. The metadata parameter is marked essential and hence RPs must always specify it.

{
  "id_token_signed_response_alg" : {
    "essential" : true,
    "one_of" : [ "PS256", "ES256" ]
  }
}
</tr>
<tr>
    <td>B</td>
    <td style="padding: 0">
{
  "id_token_signed_response_alg" :
    "PS256"
}
    </td>
    <td style="padding: 0">
{
  "id_token_signed_response_alg" :
    "PS256"
}
</tr>
<tr>
    <td>C</td>
    <td style="padding: 0">
{
  "id_token_signed_response_alg" :
    "RS256"
}
    </td>
    <td style="padding: 0">
INVALID METADATA



</tr>
Input metadata Output metadata
A
{}

INVALID METADATA

Policy operator: subset_of

The subset_of operator computes the intersection between a specified JSON array of values and a metadata parameter (also a JSON array) that is present:

  • If the resulting intersection is non-empty the metadata parameter becomes the intersection.
  • If the resulting intersection is empty the outcome depends on whether the metadata parameter is essential:
    • If the parameter is essential, the metadata is considered invalid.
    • If the parameter is voluntary it is removed from the metadata.

Scenario 1

Example policy to ensure that when RPs choose to specify a set of response types they must include the code and / or code id_token values.

{
  "response_types" : {
    "subset_of" : [ "code", "code id_token" ]
  }
}
</tr>
Input metadata Output metadata
A
{
  "response_types" :
    [ "code" ]
}
{
  "response_types" :
    [ "code" ]
}
B
{
  "response_types" :
    [ "code", "code id_token" ]
}
{
  "response_types" :
    [ "code", "code id_token" ]
}
C
{
  "response_types" :
    [ "code", "token" ]
}
{
  "response_types" :
    [ "code" ]
}
D
{
  "response_types" :
    [ "token" ]
}
{}

E

{}

    </td>
    <td style="padding: 0">
{}

Scenario 2

Example policy requiring RPs to register for a set of response types that includes the code and / or code id_token values. The metadata parameter is marked essential and RPs must always specify it.

{
  "response_types" : {
    "essential" : true,
    "subset_of" : [ "code", "code id_token" ]
  }
}
</tr>
Input metadata Output metadata
A
{
  "response_types" :
    [ "code", "token" ]
}
{
  "response_types" :
    [ "code" ]
}
B
{
  "response_types" :
    [ "token" ]
}
INVALID METADATA

C

{}

    </td>
    <td style="padding: 0">
INVALID METADATA

Policy operator: superset_of

The superset_of operator ensures a metadata parameter (JSON array) that is present includes a specified set of values.

Scenario 1

Example policy requiring RPs that choose to specify a set of grant types to include at least the authorization_code type.

{
  "grant_types" : {
    "superset_of" : [ "authorization_code" ]
  }
}
</tr>
Input metadata Output metadata
A
{
  "grant_types" :
    [ "authorization_code" ]
}
{
  "grant_types" :
    [ "authorization_code" ]
}
B
{
  "grant_types" :
    [ "authorization_code",
      "refresh_token" ]
}
{
  "grant_types" :
    [ "authorization_code",
      "refresh_token" ]
}
C
{}

{}

Scenario 2

Example policy requiring RPs to register for a set of grant types that include at least the authorization_code type. The metadata parameter is marked essential and RPs must always specify it.

{
  "grant_types" : {
    "essential" : true,
    "superset_of" : [ "authorization_code" ]
  }
}
</tr>
Input metadata Output metadata
A
{
  "grant_types" :
    [ "authorization_code" ]
}
{
  "grant_types" :
    [ "authorization_code" ]
}
B
{
  "grant_types" :
    [ "authorization_code",
      "refresh_token" ]
}
{
  "grant_types" :
    [ "authorization_code",
      "refresh_token" ]
}
C
{}

INVALID METADATA