configuration.yml
This is where you configure Nidam to make it yours.
OAuth Client Credentials
Nidam comes with a default OAuth client so it can run without any additional configuration:
client:
id: client
secret: secret
secret-hash: '{bcrypt}$2a$10$.ld6BfZescPDfVVduvu.6O9.7FLMI64l4PfvnBZJQEBhTLFFbeKei'
For local development, testing, and the demo, you can keep these values.
For production, replace them with your own credentials. The defaults are part of the open-source Nidam project and are therefore publicly known.
Choose your own client ID and a strong secret:
client:
id: nidam-clio
secret: fancypassword
secret-hash: '{bcrypt}$2a$10$zZi10CxFRhKOGY2cLOejAO7beulclLPhSbNNfYvhwBLCl9zLbTBue'
The id can be whatever you want, while secret should be a strong random value.
You can generate the BCrypt hash with an online tool such as W3Schools, bcrypt-generator, or CyberChef.
For production secrets, generating the hash locally is preferable. You can use Spring CLI (requires Java):
Windows: .\spring.bat encodepassword secret
Linux/Mac: ./spring encodepassword secret
Or bcrypt-tool:
.\bcrypt-tool.exe hash secret
Use the equivalent command for your operating system.
Host
By default, Nidam, frontend, and backend are all assumed to be running on http://localhost.
You can change the host where Nidam itself is running with:
host: http://yourhost.nidam
Your frontend and backend can also run on different hosts. For example, suppose:
- Nidam runs on
http://yourhost.nidam - Your backend runs on
http://backend.nidam - Your frontend runs on
http://frontend.nidam
In that case, configure each host separately:
# where Nidam is running
host: http://yourhost.nidam
# where your backend is running
resource-server-origin: http://backend.nidam
# where your frontend is running
react-origin: http://frontend.nidam
So, host tells Nidam where Nidam itself is hosted, while resource-server-origin and react-origin tell Nidam where to find your backend and frontend.
Ports
Nidam comes with the following default ports:
h2-embedded-port: 9092
registration-port: 4000
react-port: 4001
authorization-server-port: 4002
resource-server-port: 4003
reverse-proxy-port: 7080
bff-port: 7081
You can change any of these ports. For example:
h2-embedded-port: 2029
registration-port: 2030
react-port: 2031
authorization-server-port: 2032
resource-server-port: 2033
reverse-proxy-port: 2034
bff-port: 2035
Remember the introduction page, where you saw how to replace the default frontend and backend with your own.
The example there used Nidam's default ports. Now that you know how to configure the ports, you can run your frontend and backend on any ports you choose.
Database
Nidam uses an embedded H2 database by default. Nidam also supports the following databases:
- SQL: MySQL, PostgreSQL, MariaDB, Microsoft SQL Server, Oracle Database, and IBM DB2
- NoSQL: MongoDB
if you're switching to another SQL database, only one thing you need to change: the database url, username and password.
Switching to another SQL database
When switching from H2 to another supported SQL database, you only need to provide the connection details:
users-db-url: jdbc:mysql://localhost:3306/identity_hub
users-db-user: root
users-db-password: "CcmN*`6@3T9H%P#yg^V<7v"
You do not need to change nidam.persistence-mode.
By default, it is set to sql:
nidam:
persistence-mode: "sql"
That's why the same configuration works for H2 and any other supported SQL database.
Switching to MongoDB
MongoDB is different because it is a NoSQL database. In addition to providing the connection details, you must tell Nidam to use MongoDB:
users-db-url: mongodb://localhost:27017/identity_hub
nidam:
persistence-mode: "mongo"
The nidam.persistence-mode property accepts two values. Its default value is sql:
# sql or mongo
nidam:
persistence-mode: "sql"
Finally, some database URLs can contain the credentials themselves. When that is the case, users-db-user and users-db-password are not needed.
Session Mode
By default, Nidam stores authenticated user sessions in memory using Tomcat.
While this is suitable for development, for production Nidam should use Redis to store sessions. Using Redis during development is also recommended because it gives you visibility into the sessions Nidam is actually storing.
The nidam.session-mode property accepts two values:
# tomcat or redis
nidam:
session-mode: "tomcat"
Its default value is tomcat, since Nidam is a Spring Boot application.
Switching to Redis
To use Redis, change session-mode to redis and provide the Redis connection URL:
redis-url: redis://localhost:6379
nidam:
session-mode: "redis"
Redis Namespaces
Nidam uses two separate Redis namespaces by default:
redis-token-generator-namespace: nidam:token-generator
redis-bff-namespace: nidam:bff
These namespaces must remain different, so that the token-generator and bff services keep their Redis data separate.
You can replace nidam with your own brand or application name:
redis-token-generator-namespace: mybrand:token-generator
redis-bff-namespace: mybrand:bff
Just make sure you do not use the same namespace for both:
redis-token-generator-namespace: mybrand:same
redis-bff-namespace: mybrand:same
Backend Contract
Nidam backend source code: View on GitHub
Nidam does not require your backend to use a specific programming language, framework, or library. Instead, your backend must implement a small security contract so that it can work with Nidam.
Your backend must:
- Act as an OAuth 2.0 Resource Server.
- Validate access tokens issued by Nidam.
- Expose a public, authentication-aware profile endpoint,
/meby default. - Require authentication for all other application endpoints.
- Use the
authoritiesclaim from the access token for authorization.
The exact implementation depends on your backend framework and language.
1. OAuth 2.0 Resource Server
Your backend must act as an OAuth 2.0 Resource Server and accept Nidam access tokens as bearer tokens:
Authorization: Bearer <access-token>
The backend is responsible for validating the access token before allowing access to protected resources.
At a minimum, token validation must verify:
- the JWT signature using the public keys published by Nidam;
- the
issclaim matches the configured Issuer; - the
audclaim contains the configured Audience; - the token is currently valid according to its temporal claims such as
expandnbf.
2. Issuer
Configure your backend with the Issuer URL of the Nidam authorization server.
For example:
http://localhost:7080/auth
The issuer must be used to verify that the token was actually issued by the expected Nidam authorization server.
Where supported by your framework, use the issuer for OpenID Connect discovery so that the backend can obtain the authorization server's published signing keys.
The issuer is part of the token's identity and must not simply be assumed based on the request URL.
The issuer URL comes from your Nidam configuration:
host: http://localhost
reverse-proxy-port: 7080
reverse-proxy-uri: ${host}:${reverse-proxy-port}
authorization-server-prefix: /auth
issuer: ${reverse-proxy-uri}${authorization-server-prefix}
3. Audience
Your backend must validate the token's Audience.
The expected audience identifies the BFF in Nidam.
For example:
client
A token whose aud claim does not contain the expected audience must be rejected.
The audience is the value configured through client.id:
client:
id: client
The audience value can be configured.
4. Authorities
Nidam access tokens contain the user's granted authorities in the following claim:
{
"authorities": [
"manage-users",
"manage-projects"
]
}
Your backend must extract the values from the authorities claim and make them available to its authorization mechanism.
The values must be treated as the authority names themselves.
For example:
manage-users
manage-projects
top-secret
Do not require a framework-specific prefix such as ROLE_ unless your application deliberately translates the Nidam authority names into such a representation.
Authorization must then be performed using these authorities.
For example, an endpoint may require:
manage-users
or allow either:
manage-users OR manage-projects
Another endpoint may require:
top-secret
An authenticated user who does not possess the required authority must be denied access.
5. Protected Endpoints
All application/API endpoints other than the profile endpoint must require authentication.
An unauthenticated request to a protected endpoint must result in:
401 Unauthorized
A request containing an invalid or unverifiable access token must also result in:
401 Unauthorized
An authenticated request where the user does not have sufficient authority must result in:
403 Forbidden
The JSON structure used by the Nidam backend and frontend for a 403 Forbidden response is:
{
"status": 403,
"code": "ACCESS_DENIED",
"message": "You do not have sufficient permissions"
}
6. Public Profile Endpoint
Your backend must expose a public GET endpoint that provides the authentication state of the current caller.
The default endpoint is:
GET /me
The endpoint can be changed through configuration:
profile-public-endpoint: /me
The frontend must be configured to use the same endpoint.
This endpoint does not require authentication, but it must still process a bearer token when one is supplied.
In other words:
- no token → return anonymous information;
- valid token → return authenticated user information;
- invalid token → return
401 Unauthorized.
A successful authenticated response must contain a structure similar to the following:
{
"username": "mehdi@nidam.com",
"email": "mehdi@nidam.com",
"authorities": [
"manage-users",
"manage-projects"
],
"exp": 1791479840
}
Where:
| Field | Description |
|---|---|
username | The authenticated user's identifier. Nidam uses the user's email address as the username |
email | The user's email address, taken from the JWT email claim. |
authorities | The authorities resolved from the JWT authorities claim. |
exp | The access-token expiration time as Unix time in seconds. |
For an anonymous request, the endpoint must return:
{
"username": "",
"email": "",
"authorities": [],
"exp": 9223372036854776000
}
The Nidam frontend treats an empty email value as the unauthenticated state.
7. Responsibility of the Backend
Nidam defines what your backend must enforce, but not how it must be implemented.
For example, depending on the technology you use, you may implement the contract using:
- Spring Security;
- ASP.NET Core authentication and authorization;
- Node.js middleware;
- Go HTTP middleware;
- or the equivalent security facilities of another framework.
Your implementation is responsible for correctly translating Nidam's OAuth/JWT contract into the security model of your chosen framework.
Backend Examples
To make implementation easier, Nidam provides example resource servers for several technologies:
The repository currently contains examples for:
ASP.NET, Go, Python FastAPI, Micronaut, Jakarta EE / MicroProfile / Open Liberty, and Node.js / Express.
These examples are intended to demonstrate how the Nidam backend contract can be implemented with different technologies.
They should be treated as reference implementations, not as a guarantee that every example is production-ready.
I have experience with the Spring ecosystem used by Nidam itself, but not the same level of production expertise in every other framework or language represented in the examples.
The Spring-based backend included with Nidam is suitable for production use.
Ask GPT
You can ask GPT, or an equivalent assistant, to generate a starting template for your backend framework or library.
Give it the values it needs, such as:
- Issuer
- Audience
- JWKS endpoint, when required by the framework
/meendpoint- the
authoritiesclaim name
For example, you can provide the backend contract from this page together with your framework and configuration values and ask the assistant to generate the corresponding Resource Server, JWT validation, and authority-based authorization configuration.
Treat generated code as a starting point. You are responsible for reviewing it and ensuring that the resulting implementation correctly enforces this contract before using it in production.
Frontend Contract
Nidam frontend source code: View on GitHub
Nidam ships with a React SPA built using Create React App (CRA). It demonstrates how a frontend integrates with Nidam to register users, determine their authentication state, login, access protected backend resources, and log out.
The shipped SPA provides two example views:
/signup— the registration view, intended for unauthenticated users./secret— the authenticated view, which calls two backend endpoints to demonstrate successful access (200 OK) and denied access (403 Forbidden).
You can implement your frontend using any framework. Regardless of the framework you choose, your frontend must integrate with Nidam through its configured host URL
1. Serve Your Frontend Under a Base Path
By default, Nidam serves the frontend under the /spa path rather than at the root of the Nidam host.
For example, the frontend is accessed at:
http://localhost:7080/spa
This path is configured in Nidam:
react-prefix: /spa
If you use a different base path, such as /frontend, update Nidam's reverse proxy configuration accordingly:
react-prefix: /frontend
Your frontend's build configuration, client-side routing, and Nidam configuration must agree on the public base path.
React Create React App
For CRA, configure the base path in package.json:
{
"homepage": "/spa"
}
Also configure React Router's BrowserRouter:
<BrowserRouter basename="/spa">
Both values must match the base path configured in Nidam.
The homepage setting controls the paths used for generated build assets, while basename tells React Router which URL prefix to use for application routes.
With this configuration, the application routes /signup and /secret are available at /spa/signup and /spa/secret, respectively.
Make sure that direct navigation and browser refreshes on these routes work as well as navigation from within the SPA.
Next.js
For Next.js, configure the base path in next.config.mjs:
const nextConfig = {
basePath: "/spa",
};
export default nextConfig;
If you use another framework, consult its documentation for configuring the base path and serving the application under a subpath.
Important: If you change the base path, ensure that Nidam's
react-prefix, your frontend's routing and build configuration, and the permitted login and logout redirect URLs remain consistent.
2. Determine the Authentication State
When the frontend starts, it displays a splash screen while it determines whether the current user is authenticated.
It does so by requesting the profile endpoint through the backend:
GET http://localhost:7080/bff/api/me
The /bff and /api prefixes can be configured. The example below uses their default values.
For the examples below, REACT_APP_NIDAM_HOST_URL represents the browser-facing Nidam host URL,
including the port if required. With the default configuration, its value
is http://localhost:7080.
REACT_APP_REVERSE_PROXY_URI=http://localhost:7080
REACT_APP_RESOURCE_SERVER_URI=${REACT_APP_REVERSE_PROXY_URI}/bff/api
REACT_APP_PROFILE_PUBLIC_ENDPOINT=me
Nidam's SPA uses Axios for HTTP requests, but you can use whichever HTTP client or request mechanism you prefer. The following snippets demonstrate the approach used by the shipped SPA; Axios is not a requirement.
const resourceServerAxios = axios.create({
baseURL: CONFIG.RESOURCE_SERVER_URI,
timeout: 15000,
});
The profile request is made as follows:
const response = yield resourceServerAxios.get( CONFIG.PROFILE_PUBLIC_ENDPOINT );
Because the configured endpoint is /me, the resulting URL is /bff/api/me.
The splash screen remains visible while the initial request is being processed. Once a successful response is received, the frontend determines the appropriate view from the returned profile information.
As explained in the Backend Contract, the profile endpoint returns user information when the request is authenticated and an anonymous response otherwise.
Nidam's SPA uses the email field to determine authentication state:
- An empty
emailmeans the user is unauthenticated. - A non-empty
emailmeans the user is authenticated.
The frontend should not use the exp value or the presence of other fields as a substitute for this rule.
A failed request must also be handled separately from a successful response indicating an anonymous user.
3. Register Users
The signup view must provide a registration form and a way for existing users to navigate to the login flow.
Registration requests are sent to the Registration service through Nidam.
By default, Nidam uses /registration as the registration prefix:
REACT_APP_REVERSE_PROXY_URI=http://localhost:7080
REACT_APP_REGISTRATION_PREFIX=/registration
REACT_APP_BACKEND_REGISTRATION_URL=${REACT_APP_REVERSE_PROXY_URI}${REACT_APP_REGISTRATION_PREFIX}
The shipped SPA uses Axios for registration requests, but you can use any HTTP client:
const registerAxios = axios.create({
baseURL: process.env.REACT_APP_BACKEND_REGISTRATION_URL,
timeout: 15000,
});
Registration without reCAPTCHA
When Google reCAPTCHA is disabled, which is the default, submit the registration form to:
POST /registration/register
Content-Type: application/json
For example:
{
"email": "mehdi@nidam.com",
"password": "user-password"
}
The corresponding request in Nidam's SPA is:
const response = yield registerAxios.post("register", action.user);
Registration with reCAPTCHA
When Google reCAPTCHA is enabled, the frontend must obtain a valid reCAPTCHA response token and submit the registration request to:
POST /registration/registerCaptcha
Content-Type: application/json
The request body includes the additional recaptchaKey field:
{
"email": "mehdi@nidam.com",
"password": "<user-password>",
"recaptchaKey": "Google reCAPTCHA response token"
}
The corresponding request is:
const response = yield registerAxios.post("registerCaptcha", action.user);
The recaptchaKey field contains the response token obtained from Google reCAPTCHA, not the public site key used to obtain that token.
Nidam's reCAPTCHA configuration determines whether this additional verification is required. Your frontend must use the corresponding registration endpoint and provide the required token when verification is enabled.
A later section explains how to integrate Google reCAPTCHA in more detail.
Registration Response
A successful registration returns information about the newly registered user, including the email address and assigned authorities.
For example:
{
"id": "162",
"email": "mehdi@nidam.com",
"authorities": [
"manage-users",
"manage-projects"
],
"roles": []
}
This response confirms registration; it does not, by itself, establish an authenticated session. The user must complete the login flow to authenticate.
Duplicate Email Address
If an account already exists with the supplied email address, Nidam returns HTTP 409 Conflict.
For example:
{
"timestamp": "2026-10-09T11:46:16.896+00:00",
"status": 409,
"error": "Conflict",
"message": "Email mehdi@nidam.com already used!",
"path": "/register"
}
The timestamp and path are illustrative and may vary. The frontend should use the HTTP status code to identify the conflict and display an appropriate error message to the user.
4. Login and Authentication
Nidam handles the OAuth 2.0 authentication flow. Your frontend does not need to implement the authorization-code flow, exchange authorization codes, or manage access tokens.
To begin authentication, redirect the browser to Nidam's BFF authorization endpoint.
By default, the endpoint is:
http://localhost:7080/bff/oauth2/authorization/token-generator
The frontend can configure this URL as follows:
REACT_APP_REVERSE_PROXY_URI=http://localhost:7080
REACT_APP_LOGIN_URL=${REACT_APP_REVERSE_PROXY_URI}/bff/oauth2/authorization/token-generator
Post-login Redirect
Nidam supports redirecting the user to a destination of your choice after successful authentication. Specify the destination using
the post_login_success_uri query parameter.
For example, the following URL initiates login and requests a redirect to the signup route after authentication:
http://localhost:7080/bff/oauth2/authorization/token-generator?post_login_success_uri=http%3A%2F%2Flocalhost%3A7080%2Fspa%2Fsignup
In JavaScript, use the URL API to construct the URL and encode the redirect parameter automatically.
This is how Nidam's SPA implements its login action:
import { useLocation } from "react-router-dom";
import { CONFIG } from "../config";
const location = useLocation();
const login = (event) => {
event.preventDefault();
const currentPath =
location.pathname + location.search + location.hash;
const url = new URL(CONFIG.LOGIN_URL);
url.searchParams.set(
"post_login_success_uri",
`${CONFIG.BASE_URI}${currentPath}`
);
window.location.href = url.toString();
};
The example preserves the current frontend path, query parameters, and URL fragment when initiating login.
After authentication succeeds, Nidam redirects the browser to the accepted post_login_success_uri.
In the shipped SPA, returning to /spa/signup is intentional. The SPA checks /me to determine the user's authentication
state and then decides which view to display. For example, if the user is authenticated, the SPA can redirect them
from /signup to /secret.
This routing decision belongs to your frontend, not Nidam. Nidam is responsible for authentication, establishing the session, and redirecting the browser to the permitted destination.
NEW
Redirect Security
Nidam does not accept arbitrary redirect destinations. By default, the destination must belong to the configured Nidam host origin and permitted frontend base path.
If you change the frontend's public URL or base path, ensure the corresponding redirect configuration is updated.
5. Calling the Backend
After the user has successfully logged in, the browser holds the session cookie managed by Nidam's BFF.
When the frontend requests /bff/api/me, the BFF forwards the request to the backend. The backend returns the authenticated
user's profile, allowing the frontend to display the appropriate view.
The same mechanism is used when accessing your application's protected endpoints.
For example, suppose your backend exposes /demo, which requires either the manage-users or manage-projects authority.
Assuming the default prefixes, the URL is:
http://localhost:7080/bff/api/demo
Configure the backend base URL as described earlier:
REACT_APP_REVERSE_PROXY_URI=http://localhost:7080
REACT_APP_RESOURCE_SERVER_URI=${REACT_APP_REVERSE_PROXY_URI}/bff/api
Nidam SPA use the same Axios instance to call the endpoint:
const response = yield resourceServerAxios.get("demo");
You do not need to attach the access token or manually copy the session cookie to each request. Because the frontend and BFF are accessed through the same origin, the browser sends the applicable session cookie automatically. Nidam uses the server-side authentication state to obtain and relay the access token when forwarding the request to your backend.
Your frontend should therefore call the backend through Nidam rather than accessing the backend directly or managing bearer tokens itself.
Handling Forbidden Responses
The Nidam example backend also exposes /top-secret, which requires the top-secret authority.
A user without that authority receives 403 Forbidden. The response body is:
{
"status": 403,
"code": "ACCESS_DENIED",
"message": "You do not have sufficient permissions"
}
Your frontend should handle this response appropriately, for example by displaying an access-denied message instead of treating it as a successful request.
An authenticated user who possesses the required authority can access the endpoint successfully.
6. Logout
To log out, the frontend sends a POST request to Nidam's BFF logout endpoint.
By default:
http://localhost:7080/bff/logout
Configure the endpoint in your frontend:
REACT_APP_REVERSE_PROXY_URI=http://localhost:7080
REACT_APP_LOGOUT_URL=${REACT_APP_REVERSE_PROXY_URI}/bff/logout
Nidam supports redirecting the user to a chosen frontend location after logout using the X-POST-LOGOUT-SUCCESS-URI request header.
The following example preserves the current frontend path, query parameters, and URL fragment:
import axios from "axios";
import { useLocation } from "react-router-dom";
import { CONFIG } from "../config";
const location = useLocation();
const logout = async () => {
const currentPath =
location.pathname + location.search + location.hash;
const response = await axios.post(
CONFIG.LOGOUT_URL,
{},
{
headers: { "X-POST-LOGOUT-SUCCESS-URI": CONFIG.BASE_URI + currentPath }
}
);
window.location.href = response.headers["location"];
};
The browser automatically sends the applicable Nidam cookies with requests. Nidam's SPA uses Axios, which automatically handles the XSRF token header for same-origin requests. You do not need to manage cookies or set the XSRF header manually when using this setup.
If you use a different HTTP client, make sure it sends requests in a way that satisfies Nidam's BFF security configuration.
As with the post-login redirect, the logout destination must satisfy Nidam's redirect restrictions. It is not an unrestricted redirect to an arbitrary URL.
The logout request clears the session and the associated server-side OAuth2 authorization state, and clears the session cookie in the browser.
7. Frontend Configuration and Security
The examples in this page use React CRA environment variables. Adapt the variable names and configuration mechanism to your own framework.
Ensure that:
- The Nidam host URL and endpoint prefixes match your Nidam configuration.
- The frontend base path agrees with Nidam's
react-prefix. - The profile endpoint is requested through Nidam;
- Login and logout redirects use permitted frontend URLs;
- Registration and backend calls use the configured Nidam host paths;
- The frontend never stores or handles Nidam access tokens directly.
Remember that CRA variables prefixed with REACT_APP_ are embedded in the client-side build and are visible to users.
Never put client secrets or other confidential values in them.
In production, serve the application over HTTPS and ensure that the session cookie and all authentication-related requests are handled securely.
Password Encoders
Nidam supports four built-in password encoders: scrypt, bcrypt, argon2, and pbkdf2. You can control which encoders are available by updating the following property:
password-encoders: scrypt,bcrypt,argon2,pbkdf2
The first encoder in the list is used as the default. With the configuration above, Nidam uses scrypt to encode passwords during user registration.
For example, to use only bcrypt:
password-encoders: bcrypt
Passwords Without an Encoder ID
If you have an existing database containing passwords encoded without an encoder ID, you can specify which encoder Nidam should use to verify them during authentication.
For example, the following hash has no encoder ID:
$100801$2umc2uH6XR0Cq9Odmfl5WA==$9Dgl0ZRoCisqnx..
In contrast, a hash prefixed with {scrypt} identifies the encoder used:
{scrypt}$100801$2umc2uH6XR0Cq9Odmfl5WA==$9Dgl0ZRoCi..
To tell Nidam which encoder to use for hashes without an ID, configure the password-idless property:
password-idless: scrypt
This takes any of the four values: scrypt, bcrypt, argon2, or pbkdf2.
Authorities and password encoders are crucial parts to decide on and get right from the start—they are the foundation.
Choose your password encoder and authority model carefully from the start. Both are foundational security decisions that influence how you manage user credentials and control access to your application's resources.
Authorities : User Management Configuration
By default, Nidam Registration assigns the following authorities to every newly registered user:
authorities: manage-users,manage-projects
Authorities are application-specific and determine which operations a user is authorized to perform. You should replace the default list with the authorities required by your application, specified as a comma-separated list:
authorities: authority-1,authority-2
Define your application's authorities according to its access-control requirements.
TTL
As explained in How Long Does the User Stay Logged In?, Nidam uses token lifetimes, also known as TTL (Time To Live), to determine how long each token remains valid.
You can customize these lifetimes using the ttl property:
ttl:
id-token: 1h
access-token: 1h
refresh-token: 7d
Specify each duration using one of the following units:
m— minutes. For example,90mrepresents 90 minutes.h— hours. For example,72hrepresents 72 hours.d— days. For example,14drepresents 14 days.
Important: The refresh-token lifetime must always be longer than the access-token lifetime. Otherwise, the refresh token
may expire before the access token, preventing Nidam from renewing the access token when needed.
It is recommended to use the same lifetime for id-token and access-token, as shown in the example above.
The minimum supported lifetime for both ID tokens and access tokens is 2 minutes.