# About OpenID Connect

OpenID Connect (OIDC) is an authentication protocol based on the OAuth 2.0 protocol. OAuth 2.0 is a framework designed to support the development of authentication and authorization protocols. It provides a variety of standardized message flows based on JSON and HTTP, used by OIDC to provide Identity services. OIDC is an attempt to make authentication a more integral part of the OAuth 2.0 protocol. Thus, OIDC is an add-on to the OAuth 2.0 protocol, developed as the successor to SAML 2.0 and OpenID.

OIDC lets developers authenticate their users across websites and apps without having to own and manage password files. Authentication can be done in three different ways using OIDC (the Authorization Code Flow, the Implicit Flow or the Hybrid Flow). Signicat has implemented the first one of the three, the Authorization Code Flow. This flow will be the one described in the section below as well as in the flow diagrams.


OIDC authentication flow click-to-zoom

# Using the OIDC protocol

To get started with authentication using OIDC, refer to the Authentication quick start guide.

You can find an example implementation of OIDC authentication with Signicat here (opens new window).

# Authorization code flow

The Authorization Code Flow returns an Authorization Code to the Client, a code that the Client can exchange for an ID Token, an Access Token and a Refresh Token (optional) directly with the OIDC Authorization Server, at the Token Endpoint. This procedure provides the benefit of not exposing any tokens to the User Agent (and possibly other malicious applications with access to the User Agent). For the Authentication Server to trust the Client before exchanging any authentication data regarding the end-user the Server can authenticate the Client. Authentication Code Flow is therefore suitable for Clients that can securely maintain a Client Secret between themselves and the OIDC Authentication Server.

The Authorization Code Flow steps for performing authentication to log in the end-user (or to determine that the end-user is already logged in) are the following:

  1. The User Agent requests resources.
  2. Client prepares an Authentication Request and sends the request to the OIDC Authorization Server.
  3. The end-user is authenticated.
  4. Authorization Grant Code is requested.
  5. OIDC Authorization Server obtains end-user consent (optional).
    1. If consent is asked for but denied, the end-user will not be authorized and will not be able to access their resources. The login will be stopped.
    2. If consent is asked for and accepted, the end-user will be authorized. Continue to step 6.
  6. OIDC Authorization Server send the end-user back to the Client with an Authorization Code.
  7. Client request a response using the Authorization Code at the Token Endpoint (OIDC Authorization Server).
  8. Client receives a response that contains an ID Token, an Access Token and a Refresh Token (optional) in the response body (among other parameters).
  9. Client validates the ID Token, retrieves the end-user's Subject Identifier and request resources.

OIDC authentication flow click-to-zoom

# Endpoints

The following endpoint URLs are available for communicating with the OpenID Connect provider through Signicat.

# Authorization

The Authorization Endpoint performs authentication of the end-user. Authentication is done using the request parameters listed below:

  • scope: Required. The OpenID scope value specifies the behaviour.
  • response_type: Required. The Response Type value determines the authorization processing flow to be used, including what parameters are returned from the endpoints used. When using the Authorization Code Flow, this value is code.
  • client_id: Required. Client Identifier valid at the Authorization Server.
  • redirect_uri: Required. Redirection URI to which the response will be sent. This URI must exactly match one of the Redirection URI values for the Client pre-registered at the OpenID Provider. When using the Authorization Code Flow, the https scheme should be used (http may be used).
  • state: Required. Opaque value used to maintain state between the request and the callback.
  • nonce: Optional. String value used to associate a Client session with an ID Token, and to mitigate replay attacks.
  • prompt: Optional. Space delimited, case sensitive list of ASCII string values that specifies whether the Authorization Server prompts the end-user for re-authentication and consent. The values are:
    • none: The Authorization Server must not display any authentication or consent user interface pages. An error is returned if and end-user is not already authenticated or the Client does not have a pre-configured consent for the requested Claims, or does not fulfill other conditions for processing the request. Examples of error codes: login_required or interaction_required.
    • login: The Authorization Server should prompt the end-user for re-authentication. If it cannot re-authenticate the end-user, it must return an error typically login_required.
    • consent: The Authorization Server should prompt the end-user for consent before returning information to the Client. If consent is not obtained, it must return an error, typically consent_required.
    • select_account: The Authorization Server should prompt the end-user to select a user account. This enables an end-user who has multiple accounts at the Authorization Server to select among the multiple accounts that they might have current sessions for. If the selected account can’t be obtained, it must return an error, typically account_selection_required.
  • max_age: Optional. Maximum Authentication Age specifies the allowable elapsed time in seconds since the last time the end-user was actively authenticated.
  • ui_locales: Optional. The end-user’s preferred languages and scripts for the user interface as a space-separated list (for instance: fr en).
  • id_token_hint: Optional. ID Token previously issued by the Authorization Server being passed as a hint about the end-user’s current or past authenticated session with the client.
  • login_hint: Optional. Hint to the Authorization Server about the login identifier the end-user might use to log in.

Important

Each attribute requires its own login hint. These need to be specified in the request using the format in the example Authorization Request below. Contact Signicat to get the correct values of hints for a particular authentication method.

  • acr_values: Optional. Requested Authentication Context Class Reference values. Space-separated string that specifies the ACR values that the Authorization Server is being requested to use for processing the Authentication Requested. The full name of these values will depend on your configuration, but the format is urn:signicat:oidc:method:<name-of-method> for methods and urn:signicat:oidc:portal:<name-of-portal> for portals.
  • signicat_profile: The graphical profile to use for this request. Contact Signicat for the list of possible values for your Client.
  • request: Used for providing the authorization request parameters to Signicat in the form of a signed and/or encrypted JWT, to prevent the theft or modification of sensitive parameters.

Example authorization request

GET /oidc/authorize?
    respose_type=code
    &scope=openid profile email
    &client_id=client01
    &state=af=ifjsldkj
    &redirect_uri=https://server.example.com:443/oidcclient/redirect/client01
    &acr_values=urn:signicat:oidc:method:scid-proof
    &login_hint=deviceId-92855960
    &login_hint=authType-email

# Token

To obtain an Access Token, an ID Token, and optionally a Refresh Token, the Client sends a Token request to the Token Endpoint to obtain a Token Response.

Example token request

POST /oidc/token HTTP/1.1
    Content-Type: application/x-www-form-urlencoded
    Authorization: Basic czZCaGRSa3FOMzpnWDFmQmFOM2JW
    grant_type=authorization_code
    &code=SplxlOBeZQQYbYS6WxSbIA
    &redirect_uri=http%3A%2F%2Fclient.example.org%2Fcb

Example token response

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
{
    "access_token": SIAV32hkKG
    "token_type": "Bearer",
    "refresh_token": "8xLOxBtZ8",
    "expires_in": 3600,
    "id_token": "eyJ ... zcifQ.ewo ... NzAKfQ.ggW8h ... Mzqg"
}​

# UserInfo

To obtain the requested Claims from the UserInfo Endpoint, the Client makes a request using an Access Token obtained through OpenID Connect Authentication.

Example UserInfo request

POST /oidc/userinfo HTTP/1.1
Accept: application/json
Authorization: Bearer fAAdL01c6QWDbPs9HrWHz5e7nRWVAnxqTTP7i88G

Example UserInfo response for valid access token

HTTP/1.1200OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
{
    "sub": "bob"
    "groupIDs": ["bobsdepartment","administrators"],
    "given_name": "Bob",
    "name": "Bob Smith",
    "email": "bob@mycompany.com",
    "phone_number": "+1 (604) 55-555-66-777",
    "address": {"formatted": "123 Main St., Anytown, TX 77777"},
    "picture": "http://mycompany.com/bob_puoto.jpg"
}

# Claims

At the heart of it all are OIDC claims; an attempt to standardize all the different pieces of information about a user. A claim may for instance be a user’s surname or email address, which makes claims very similar to SAML Assertions. However, claims in OIDC are represented (as everything else in Oauth2.0/OIDC) as JSON key-value pairs.

Where to get claims?

The OIDC specification details sources of claims: the ID token and the UserInfo endpoint.

The ID token is a signed JSON object (a JSON Web Token, or JWT), containing information about the authentication a user has undergone in order to obtain the ID token. While the ID token is very similar to a SAMLResponse object in that it is a signed proof of authentication, there is one vital difference: The ID token does not in principle contain information about the user, apart from a user ID (named the subject ID). Custom claims may be contained within an ID token if relevant as authentication metadata.

The Userinfo endpoint is a separate endpoint that accepts access tokens and returns information about the user. Since an access token represents an authorization from the user to the client to perform actions on the user’s behalf, only information which the user has authorized should be returned. The userinfo claims that can be returned are largely standardized but can be infinitely extended.

# Error codes

Signicat uses HTTP response status codes (opens new window) to report the result of your requests back to you. If your request fails, an error using the appropriate status code is returned.

In general, you can expect status codes from Signicat in the following ranges:

  • 2xx success status codes confirm that your request worked as expected.
  • 4xx error status codes indicate an error caused by the information you provided.
  • 5xx error status codes indicate an error caused by Signicat's servers response.

The following is a list of the most common error codes you may encounter when integrating with Signicat's services using the OIDC protocol (the list is not exhaustive).

HTTP response code Code Description Actions available
400 INVALID_REQUEST The request contained invalid parameters. Verify that the request parameters are valid.
400 INVALID_CLIENT The provided client ID is not recognized in this Authorization server. Verify that the client configuration is correct, i.e. make sure that the way the client credentials are sent matches the client configuration.
400 INVALID_GRANT The provided authorization grant (e.g. authorization code, resource owner credentials) or refresh token is invalid, expired or revoked. Verify the validity of the authorization grant or refresh token.
400 UNSUPPORTED_GRANT_TYPE The provided grant type is unsupported. Supported grant types can be viewed by visiting the pre-production environment (opens new window) or the production environment (opens new window). Enter a valid grant type and resubmit the request.
400 UNSUPPORTED_RESPONSE_TYPE The provided response type is invalid. The authorization server does not support the response type in the request. Fix and resubmit the request.
400 UNSUPPORTED_TOKEN_TYPE The provided token type is invalid. The authorization server does not support the token type in the request. Fix and resubmit the request.
400 INVALID_SCOPE Your "scope" or "claims" parameters contain invalid values. Supported scopes can be viewed by visiting the pre-production environment (opens new window) or the production environment (opens new window). Fix and resubmit the request.
400 LOGIN_REQUIRED The authorization server requires end-user authentication.
400 CONSENT_REQUIRED The authorization server requires end-user consent.
400 REQUEST_URI_NOT_SUPPORTED This server does not support the request_uri parameter.
400 INVALID_REDIRECT_URI The value of one or more redirect_uri parameters is invalid. Verify the redirect_uri parameters and retry.
400 INVALID_CLIENT_METADATA The value of one of the Client Metadata fields is invalid and the server has rejected this request. Verify the Client Metadata fields and retry.
400 UNAUTHORIZED_CLIENT Your client is unauthorized. Provide credentials and retry.
401 INVALID_TOKEN The bearer token provided in the authorization header was not valid.
403 ACCESS_DENIED Your access to this resource is denied. Check your credentials and retry
403 INSUFFICIENT_SCOPE The provided bearer token has insufficient scope, resource cannot be accessed.
500 SERVER_ERROR Internal server error. These errors can result from temporary conditions. The client application might explain to the user that its response is delayed because of a temporary error. Retry the request.

# Additional security considerations

The base implementation of OIDC should be secure enough in most cases. This page mentions a few measures that can be taken to increase security, if desired.

In an OIDC flow, you will receive an access token that is signed by Signicat, which you have to use to fetch the user info response. The rest of this section shows how Signicat supports message encryption and signing with OIDC.

  • Encryption algorithm: AES-128
  • Supported key length: 2048-bit (4069-bit too, if required)
  • Signature hash: SHA-256

# ID token

Signing: signed according to specification. Encryption: optional, off by default. Content: see example payload below.

{
  "sub": "pc_Chm_FISDkwcSSryfWTpHgK3G6pax4",
  "acr": "urn:signicat:oidc:method:nbid",
  "aud": "demo-preprod",
  "nbf": 1568359576,
  "amr": "urn:ksi:names:SAML:2.0:ac:BankID-NO",
  "auth_time": 1568359476,
  "iss": "https://preprod.signicat.com/oidc",
  "exp": 1568363176,
  "iat": 1568359576
}

# User info response

Signing: optional, off by default. Encryption: optional, off by default. Content: contains all claims available from the scopes that the user has given consent to. Depends on the ID method.

# Encryption of the request object

One of the options for increased security is Full Message-Level Encryption (MLE). This section explains the steps that must be followed to establish MLE with OIDC.

# Prerequisites

Before the implementation, you must provide Signicat with an encryption key, so that we can encrypt our responses with it. This key needs to be in a specific format. Follow these steps:

  1. Generate a JWK RSA pair (2048-bit). Signicat also supports 4096-bit if required. It is important that you create a JWK and not a PEM, CER, CRT, etc.
  2. Send the public part to Signicat. The public part can be sent through email, as it does not contain sensitive information.

Note

When we store your key in our system, a new Key ID ("kid") will be generated. We will provide you with this new Key ID. You have to use this Key ID, as we do not have the ability to change the Key ID in our keystore.

# Implementation

You should send your requests as a normal OIDC request (see exception below). The difference between a normal OIDC flow and MLE flow are:

  1. The ID token and the response from user info is a nested JWT which is encrypted and signed.
    1. Decrypt it with your private key from the RSA pair given to Signicat.
    2. Deserialize the resulting signed JWT and verify the signature.
  2. The ID token must, as always, be verified according OIDC specifications.

Note

Below, <ENV> equals preprod.signicat.com for pre-production and your Signicat subdomain for production.

A functional example implementation of full message-level encryption can be found on GitHub (opens new window). This example is related to FTN (Finnish Trust Network).

# Encrypting authorization requests

Normally, authorization requests do not contain any personal data, and as such do not need to be encrypted. There are some unlikely edge-case scenarios where you might include personal data in the authorization request. If your implementation requires it, here’s what you should do:

Begin crafting the OIDC Authorization Request. The parameters are standard OIDC parameters. Examples of Authorization Request encryption in a number of common languages can be found on GitHub (opens new window). The requirements are as follows:

  • The HTTP request can be made using either GET or POST.
  • The payload must be a Request Object (per OIDC Core specifications, section 6.1). An example for a typical payload Request Object looks as follows: [payload example + value descriptions]
  • The request must be an encrypted JWT; which contains the aforementioned Request Object (as detailed on the OIDC specification).
  • The JWE token must be encrypted with the public key ("use":"enc") available at https://<ENV>.signicat.com/oidc/jwks.json.
  • The protected header for the JWE token must contain the following claims:
    • "enc"="A128CBC-HS256"
    • "typ"="JWE"
    • "kid" and "alg" (the values for kid and alg are specified at https://<ENV>.signicat.com/oidc/jwks.json).

# Full flow example

# Authorization

Take your client_id and client secret and concatenate them with a colon sign in between (like this -> client_id:client_secret) and Base64-encode the result. Put it in a text file.

https://preprod.signicat.com/oidc/authorize?response_type=code&scope=openid+profile&client_id=demo-preprod&redirect_uri=https://labs.signicat.com/redirect&state=123abc&acr_values=urn:signicat:oidc:method:idin

Set state to anything.

acr_values define what ID method to use. As you can see from the example URI, idin will be used. To use other methods, modify the value following acr_values with the desired method name.

redirect_uri must be configured for the client and character-for-character exactly the same.

Paste that URI into your browser and complete the flow. You should end up at the redirect URI with two parameters in the URI in the address bar: code and state. The state should be the one you supplied in the initial request.

# Token

Copy the code you got and paste it into the following URL request (remember to change client_id and the hostname to the correct ones):

curl -XPOST "https://preprod.signicat.com/oidc/token" -H "Authorization: Basic ZGVtby1wcmVwcm9kOm1xWi1fNzUtZjJ3TnNpUVRPTmI3T240YUFaN3pjMjE4bXJSVmsxb3VmYTg=" -d "client_id=demo-preprod&redirect_uri=https://labs.signicat.com/redirect&grant_type=authorization_code&code=CODE GOES HERE"

Important

  • The redirect URI must be the same as the initial one.
  • The header, as shown, must be "Authorization: Basic [the base64-encoded credentials you made in the first step]"
    • In this case, we have base64-encoded "demo-preprod:mqZ-_75-f2wNsiQTONb7On4aAZ7zc218mrRVk1oufa8"
  • Paste the code in the code parameter.

Now, run that command. You should get JSON containing an access token, a refresh token (depending on the config), and an ID token. Copy the access token string.

# UserInfo

It’s time to use the access token to return a JSON containing your information. Run:

curl -XGET "https://preprod.signicat.com/oidc/userinfo" -H "Authorization: Bearer [your access token]"

# Differences between OIDC and SAML 2.0

In addition to that JSON is used instead of XML, there are some other important differences:

  1. The user is in control of their data. OIDC trusts clients less than the SAML protocol does. The client can only access the users’ data (claims) when the user has authorized access to their data. The user is the legal owner of their personal data, and this construct ensures the protocol is aligned with that idea.
  2. The client explicitly requests access to resources. Everything that we know about the user will be returned in the SAMLResponse. In OAuth 2.0 and OIDC, the client is expected to request access to data and services through Claims and scope. This helps with only transferring data that is necessary, and ensuring users can control what is shared about them.
  3. The client accesses resources directly. The SAMLResponse is transferred to clients through the user agent (browser) and is therefore impacted by user data transfer rates. OIDC resources are accessed by the client directly using access tokens and can therefore be done at any time and without involving the user further. This also ensures one does not put too much trust in the user’s user agent, by avoiding transfer of sensitive information through it, like SAML does.
  4. Access granted to clients is not restricted to user information. An access token can be used for infinitely many things. As long as a resource server accepts an access token (and a scope value is defined for the action), the resource server can perform actions on behalf of the user. For instance, resource servers that create posts on your Facebook wall or change your profile information are real-life uses of this functionality.
  5. The ID token is signed using a key that is publicly available on a standardized endpoint. The OIDC standard contains a public configuration endpoint where clients can fetch information about the authorization setup. Among the data the client can get from this endpoint, is the public part of the key that was used to sign the ID token. Therefore, signature key rotation is very simple, as all clients will (should) pick up new keys from this endpoint.

# Finnish Trust Network (FTN) specifics

Due to requirements from Traficom, you are required to use Full Message-Level Encryption for authentication with the Finnish Trust Network (FTN). This section details the steps required to set up MLE for OIDC.

# Prerequisites

We need you to provide an encryption key, so that we can encrypt our responses with this key. This key needs to be in a specific format:

  1. Generate a JWK RSA pair (2048-bit). Signicat also supports 4096-bit if required. It is important that you create a JWK and not a PEM, CER, CRT, etc.
  2. Send the public part to Signicat. The public part can be sent through email as it does not contain sensitive information.

Note

When we store your key in our system a new Key ID ("kid") will be generated. We will provide you with this new Key ID. You have to use this Key ID, as we do not have the ability to change the Key ID in our keystore.

# Implementation

You should send your requests as a normal OIDC request (see exception below). The difference between a normal OIDC flow and MLE flow are:

  1. The ID token and the response from user info is a nested JWT which is encrypted and signed.
    1. Decrypt it with your private key from the RSA pair given to Signicat.
    2. Deserialize the resulting signed JWT and verify the signature.
  2. The ID token must, as always, be verified according OIDC specifications.

Note

<ENV> equals preprod.signicat.com for pre-production and your Signicat subdomain for production.

A functional example implementation of full message-level encryption for FTN can be found on GitHub (opens new window).

# Encrypting authorization requests

The instructions from Traficom specify "all personal data shall be encrypted and signed at the message level". Normally the authorization request itself contains no personal data, and as such it does not need to be encrypted. However there does exist certain unlikely edge-case scenarios where you might include personal data in the authorization request.

Note

FTN does not support pre-filling of national identity numbers, so this should not be a valid use case.

If your implementation requires it, here is our guide to implementing encrypted authorization requests:

Begin crafting the OIDC Authorization Request. The parameters are standard OIDC parameters. Examples of Authorization Request encryption in a number of common languages can be found on GitHub (opens new window). The requirements are as follows:

  • The HTTP request can be made using either GET or POST.
  • The payload must be a Request Object (per OIDC Core specifications, section 6.1). An example for a typical payload Request Object looks as follows:
{
    "login_hint": ["subject-210281-9988"],
    "ui_locales": "en",
    "scope": "openid profile signicat.national_id",
    "acr_values": "urn:signicat:oidc:method:ftn-nordea-auth",
    "response_type": "code",
    "redirect_uri": "https://labs.signicat.com/redirect",
    "state": "state123",
    "client_id": "CLIENTID",
}
Value Type Required
login_hint List of strings No
ui_locales String No
scope String Yes
acr_values String Yes
response_types String Yes
redirect_uri String Yes
state String Yes
client_id String Yes
  • The request must be an encrypted JWT, which contains the aforementioned Request Object (as specified at https://openid.net/specs/openid-connect-core-1_0.html#JWTRequests).
  • The JWE token must be encrypted with the public key ("use":"enc") available at https://<ENV>.signicat.com/oidc/jwks.json.
  • The protected header for the JWE token must contain the following claims:
    • "enc"="A128CBC-HS256"
    • "typ"="JWE"
    • "kid" and "alg" (the values for "kid" and "alg" are specified at https://<ENV>.signicat.com/oidc/jwks.json).
Last updated: 3/1/2021, 12:00:45 AM