Getting Started
Learn about key security guidelines for implementing basic OpenID Connect authentication in client applications.
In OpenID Connect(OIDC) authentication flows, there are two main roles:
Criipto Verify is an OpenID Provider, handling most of the process. However, it is important for developers of client applications to also follow security best practices.
The most secure method of performing OIDC authentication is the Authorization Code Flow, or its extended version — Authorization Code Flow with PKCE.
In the Authorization Code Flow, the client application exchanges an authorization code for tokens at the token endpoint. When using Criipto Verify for eID authentication: After the end user successfully logs in with their eID and is redirected back to the client application through the redirect URL, the client application retrieves the authorization code from the URL. The client application then uses this code to request an ID token from Criipto Verify (see code for token exchange).
The Authorization Code Flow enhances security by mitigating replay attempts by attackers (when an attacker tries to reuse a valid intercepted token) and generally reduces the attack surface since ID tokens are not exposed in URLs.
Best practice:
nonce
parameter and the respective claim in the id_token
, and one-time tokens carried in the state
parameter.nonce
is used to associate an ID token to the specific authorization request and user session.
The client application should bind nonce
to the user agent session and send it with the initial authorization request to the OpenID Provider. The binding is done using HTTPOnly, Secure cookies, and preferably with a server-side encrypted value for the nonce
(using authenticated encryption).
The OpenID Provider puts the received nonce
value into the id_token
that is issued as part of the code exchange at the token endpoint.
nonce
serves as a token validation parameter. If an attacker injects an authorization code in the authorization response, the nonce
value in the client session and the nonce
value in the id_token
received from the token endpoint will not match, and the attack will be detected. nonce
also helps protect against an attacker potentially intercepting a valid state
parameter, but then providing a code
value tied to a different session. This could be a concern for public clients, and, in theory, in some confidential client scenarios.Best practice: For confidential clients implementing the Authorization Code Flow, it is strongly recommended to always include a nonce
parameter in authorization requests to protect against misuse of authorization codes.
The client application should then validate the nonce
in the received id_token
, and not use any issued tokens until this check has succeeded.
For public clients using the PKCE flow, the nonce
parameter can also provide an additional layer of security. However, it should only be used in addition to PKCE, not as a substitute for it.
The state
parameter helps prevent Cross-Site Request Forgery (CSRF) attacks by maintaining state between the client application and the authorization server.
When initiating an authorization request, the client application generates a random value and includes it in the state
parameter.
This random value links the request to the redirect URL to the client session. Once the user is authenticated, the authorization server redirects the user back to the client application's redirect URL, including the same state
value in the URL. For example: https://your-app.com/callback?code=authorization-code&state=unique-state-value
Similarly, if the state
parameter was included in the authorization request, the error responses from the authorization server will also contain the state
parameter, providing protection against attacker-forged error responses.
Overall, the state
parameter allows the client application to verify that the authorization response is genuine and was sent by the authorization server in response to the original authorization request.
Best practice: Always generate a unique, random state
value for each authorization request and validate it when the response is received.
Upon successful user authentication, Criipto Verify will issue an ID token to the client application. id_token
contains user authentication information in the form of a JSON Web Token (JWT).
However, receiving a JWT is not enough - your application must also validate it. Without validation, there’s no guarantee that the token hasn’t been tampered with or forged.
Note: id_token
must be validated, even if using the /userInfo
endpoint for personal data.
Best practice: Always delegate token validation to trusted libraries like jose or choose one of Criipto's integrations. Libraries like these handle all the complexities involved in checking JWT signatures, token expiration, etc. Manual validation should be avoided. More information on how JWT validation works is available in our JWT validation guide.
For client authentication, it is recommended to use asymmetric cryptography, such as Private Key JWTs. This provides stronger security compared to symmetric key methods.
When using asymmetric cryptography, authorization servers do not need to store sensitive symmetric keys, reducing the risk of key leakage. Additionally, key rotation is simplified because you can provide a JWT keys set in a URL, allowing Criipto Verify to dynamically fetch the updated keys.
Best practice: Use Private Key JWTs for client authentication to enhance security and simplify key management.
The Implicit Flow has been deprecated and is considered insecure due to its vulnerability to token leakage and token replay attacks. Client applications should not use the Implicit Flow or any other method that causes the authorization server to issue tokens directly in the authorization response (such as response_type=id_token
).
Tokens in the Implicit Flow are exposed in the URL fragment (response_mode=fragment
), making them vulnerable to interception and mishandling. While response_mode=fragment
is convenient and easy to use during development and testing, it is insecure for production applications for several reasons:
For improved security, use response_mode=query
, which returns authorization parameters in the query string of the redirect URL. This approach is more secure and is the default response_mode
for the Authorization Code Flow and PKCE.
For detailed information on security requirements and other recommendations for clients and servers implementing OAuth 2.0 and OpenID Connect, check OAuth 2.0 Security Best Current Practice.