OpenID Connect
Introduction
LoginID supports OpenID Connect to enable easy integrations that require very little effort. This document explains the supported features, how to get started and how to use it.
Overview
LoginID supports OpenID Connect as an OpenID Provider (OP) and allows developers to sign up, register applications and leverage passkeys within their applications without having to implement support for passkeys themselves. Application users register and sign up within the developer's project (which is like a tenant ID) during the authentication and authorization flows. Developers will find an overview of application users within the customer dashboard.
Getting started
To begin utilizing LoginID's OpenID Connect (OIDC) support, the first step is to signin on LoginID's customer dashboard. Following signin, you'll need to create an OIDC project and application.
Creating OIDC Project
After signing in to the dashboard proceed with the following:
- Go to the advanced setup page.
- Select
OIDC
project type. - Enter
Project Name
. - Press
Confirm
button. - Go to
Settings - OIDC
section. - This is where you can find all relevant endpoints.
Create OIDC Application
In OAuth, applications
are commonly referred to as clients
.
Public Application
It is recommended to make your application public if your client application falls into any of these categories:
- Single-page applications (SPAs).
- Mobile applications without a secure backend.
- Clients running in environments where securing a client secret is challenging.
Steps
- Click on
Application
tab. - Click on
+ Add Application
- Select
OpenID Connect (OIDC)
. - Enter
Application Name
. - Enter
Redirect URIs
. This is the URL to which LoginID redirects users after finishing the authorization_code flow. - Select wanted
scopes
and/or enter anyCustom Scopes
. These values are the only ones LoginID will grant and only those will be displayed to application users during the authorization flow. - Click
Create
. - Obtain the
application ID
.
Confidential Application
It is recommended to make your application confidential if your client application falls into any of these categories:
- Web applications running on a server.
- Mobile applications with a secure backend.
- Applications where the client can securely store and manage a client secret.
Steps
- Click on
Application
tab. - Click on
+ Add Application
- Select
OpenID Connect (OIDC)
. - Enter
Application Name
. - Enter
Redirect URIs
. This is the URL to which LoginID redirects users after finishing the authorization_code flow. - Select wanted
scopes
and/or enter anyCustom Scopes
. These values are the only ones LoginID will grant and only those will be displayed to application users during the authorization flow. - Click
Generate Key Pair
to generate an ES256 private key (more info in here). - Click
Create
. - Obtain the
application ID
.
Well-Known Endpoint
{{issuer URL}}/oidc/.well-known/openid-configuration
endpoint serves as the discovery endpoint, providing a dynamic and standardized way for client applications to retrieve configuration information about an OpenID Connect provider.
Find the project issuer URL under Settings - OIDC
in your project.
Generating a client_secret
Generating a client_secret
requires a ES256 private key
to first be generated when creating a confidential application. Clicking on Generate Key Pair
will create an ES256 keypair
through the Web Crypto API. Please note that the private key is visible only once and can be copied and securely stored on your end. The public key will be transmitted to LoginID and used for verifying a signed client_secret
with the corresponding private key.
The client_secret
is a signed JWT with specific required information. You can use any cryptography library that supports ES256 private key signing for token creation.
{
"iss": "<application ID>",
"sub": "<application ID>",
"aud": "<hostname of your project issuer URL>",
"exp": "<expiry date of the token in epoch seconds>"
}
Here is an actual example:
{
"iss": "AcdrRdnMcfvnQu1YZWuw9Q",
"sub": "AcdrRdnMcfvnQu1YZWuw9Q",
"aud": "8n3y7rz3a0zigtqsh-olpq.gen2.playground.loginid.io",
"exp": 1717564137
}
Generated JWT:
eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJBY2RyUmRuTWNmdm5RdTFZWld1dzlRIiw
ic3ViIjoipppWNkclJkbk1jZnZuUXUxWVpXdXc5USIsImF1ZCI6IjhuM3k3cnozYTB6aWd0cXNoLW9scHE
uZ2VuMi5xYS5sb2dpbmlkLmlvIiwiZXhwIjoxNzE3NTY0OTk1LCJpYXQiOjE3MDIwMTI5OTV9.mZ3dm_
JFvIj8qPgJZ1n7oLz63G-ctfUz0WL6BBuo8RAFj3wNOsEoD0neeLGH6mZgHDohAtWUGrbZYmbfUSWGTQ
Find the project issuer URL under Settings - OIDC
in your project.
Initializing an authorization flow
Initialize the authorization code flow
Always URL encode any parameter values.
Typically, a client redirects users to the authorization endpoint like this:
Public Applications
curl -X GET "{{base_url}}/oidc/auth" \
-d "client_id={{app_id}}" \
-d "redirect_uri={{redirect_uri}}" \
-d "response_type=code" \
-d "code_challenge={{code}}" \
-d "code_challenge_method=S256" \
-d "scope=openid offline_access" \
-d "state={{state}}" \
-d "nonce={{nonce}}"
Private Applications
curl -X GET "{{base_url}}/oidc/auth" \
-d "client_id={{app_id}}" \
-d "redirect_uri={{redirect_uri}}" \
-d "response_type=code" \
-d "scope=openid offline_access" \
-d "state={{state}}" \
-d "nonce={{nonce}}"
Parameter Description
- client_id (required): The unique identifier for your client application.
- redirect_uri (required): The URI to which LoginID will redirect the user after authentication.
- response_type (required): The response type requested. Use code to indicate that the response will include an authorization code.
- code_challenge (required for public applications): A code verifier challenge generated by the client.
- code_challenge_method (required for public applications): The method used to transform the code verifier into a challenge. Set to S256 for the SHA-256 transformation.
- scope (required): The requested scopes for the access token. Include a space-separated list of scopes such as
openid email offline_access
. - state (recommended): A random value generated by the client, which will be included in the response to mitigate CSRF attacks.
- nonce (recommended): A random value generated by the client, which will be included in the ID Token to associate it with the user's session.
LoginID will then handle the authentication flows and will allow the client applications to request user consent.
Once LoginID has handled the user authentication and authorization it will redirect the user back to the client.
The redirect includes either of these parameter combinations:
//success
{redirect_uri}?code={authorization_code}&state={state}
//error
{redirect_uri}?error={error}&error_description={error_description}
Token Response
After receiving the authorization_code the client has to exchange it for a token response which includes an access_token and an id_token. Depending on the grant type, the token request payload will differ.
authorization_code
code_verifier (PKCE)
If you are using a public application you can use authorization_code
grant to exchange your token. code_verifier is the original code verifier used during the authorization code request (code_challenge).
curl --request POST '{{base_url}}/oidc/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id={{client_id}}' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'code={{authorization_code}}' \
--data-urlencode 'redirect_uri={{redirect_uri}}' \
--data-urlencode 'code_verifier={{code_verifier}}'
For confidential applications, you have three authentication methods to choose from.
A generated client_secret is required.
client_secret_basic
curl --request POST '{{base_url}}/oidc/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Basic {{client_secret}}' \
--data-urlencode 'client_id={{client_id}}' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'code={{authorization_code}}' \
--data-urlencode 'redirect_uri={{redirect_uri}}'
client_secret_post
curl --request POST '{{base_url}}/oidc/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id={{client_id}}' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'code={{authorization_code}}' \
--data-urlencode 'redirect_uri={{redirect_uri}}' \
--data-urlencode 'client_secret={{client_secret}}'
private_key_jwt
curl --request POST '{{base_url}}/oidc/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id={{client_id}}' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'code={{authorization_code}}' \
--data-urlencode 'redirect_uri={{redirect_uri}}' \
--data-urlencode 'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' \
--data-urlencode 'client_assertion={{client_secret}}'
refresh_token
The refresh_token
flow is used to obtain a new access token by presenting a refresh token to LoginID. This flow is designed to extend the lifetime of an authenticated session without requiring the user to re-enter their credentials.
Refresh token will be returned if offline_access
scope was requested.
curl --location --request POST '{{base_url}}/oidc/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id={{app_id}}' \
--data-urlencode 'grant_type=refresh_token' \
--data-urlencode 'refresh_token={{refresh_token}}' \
--data-urlencode 'redirect_uri={{redirect_uri}}'
client_credentials
The client_credentials
flow is a grant type designed for scenarios where a confidential client needs to access resources it owns or manages, without the involvement of a user. In this flow, the client authenticates itself directly to LoginID and obtains an access token, which is then used to access protected resources. It is typically used for machine-to-machine communication where machines or services need to communicate securely without user involvement.
One of the three authentication methods can be used. Just replace grant_type
with client_credentials
.
Response
The successful response (status: 200) will contain these values:
Refresh token will be returned if offline_access
scope was requested.
{
"id_token": "<id_token>",
"refresh_token": "<refresh_token>",
"access_token": "<access_token>",
"token_type": "Bearer",
"expires_in": 3600
}
An error response (status: >= 400) will have this structure:
{
"error": "<error-reason>",
"error_description": "<error-details>"
}
Processing the token response
The token endpoint provides an id_token
and access_token
. Here's how LoginID allows you to utilize them.
ID Token
This token is expressed as a JSON Web Token and its content adheres to the OpenID Connect core specification. It represents an authenticated user.
It is recommended to validate the claims.
- verify that aud matches the app_id
- verify that iss matches issuer as specified in the openid-configuration
- verify that exp is in the future
- verify that nonce matches the value that was included in the initial authorization request
- verify the jwt-signature
- LoginID's GET /oidc/keys may be used to retrieve the required public key
- According to OpenID Connect core, the jwt-signature validation MAY be skipped if the
id_token
was received via https, directly from the issuer
- Use sub of the id_token as user identifier within your application.
Use the id_token
as id_token_hint
on other platforms that accept a LoginID issued id_token
as credential.
Userinfo Endpoint
This endpoint serves as the endpoint where the client application can retrieve claims and details about the user. However, some of the retrievable information is also included in the id_token
claim.
curl --request POST '{{base_url}}/oidc/userinfo' \
--header 'Authorization: Bearer {{access_token}}'
curl --request GET '{{base_url}}/oidc/userinfo' \
--header 'Authorization: Bearer {{access_token}}'
Revocation Endpoint
This endpoint enables a client to request the revocation of an access token or refresh token, making it invalid. At LoginID, if either the access token or refresh token is revoked, the user will be unauthorized.
curl '{{base_url}}/oidc/revoke' \
--header 'Content-Type: application/json' \
--data '{
"token": "{{access_token}}"
}'
curl '{{base_url}}/oidc/revoke' \
--header 'Content-Type: application/json' \
--data '{
"token": "{{refresh_token}}"
}'
Introspective Endpoint
This endpoint allows a resource server to query LoginID to verify the validity and status of an access token.
curl '{{base_url}}/oidc/introspect' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'token={{access_token}}'
More information
For specific questions or feedback, please feel free to contact support@loginid.io!