Make It Yours
There are two main parts that you can and should customize:
application.yml
for Spring services and.env
for the SPAkeystore.jks
- you must absolutely change this and not use the provided one for production
π₯ User Management Configuration: Registration Serviceβ
Users in the database are saved with their email and password hash. User authorities are saved in their own table, and the relationship between users and authorities is maintained through a join table. MongoDB support is planned for future versions.
The authorities value is very important. It's supplied to the Registration Service in application.yml
:
custom:
authorization:
authorities:
- manage-users
- manage-projects
Nidam uses 'manage-users' and 'manage-projects' for demonstration purposes. Replace them with your own list. You'll find code in the repository that relates to roles, but they're currently not supported (planned for future versions).
Password Encodersβ
Nidam comes with built-in support for these encoders: scrypt, bcrypt, argon2, and pbkdf2. You can restrict the encoders by changing the declaration:
custom:
password:
encoders:
- scrypt
- bcrypt
- argon2
- pbkdf2
The first algorithm in the list is selected as the default. In this case, user registration passwords are encoded with scrypt
.
For example, if you're only interested in using bcrypt:
custom:
password:
encoders:
- bcrypt
If you have an existing database with passwords encoded without an ID (for example,
$100801$2umc2uH6XR0Cq9Odmfl5WA==$9Dgl0ZRoCisqnx..
missing the {ID}
prefix, as opposed
to {scrypt}$100801$2umc2uH6XR0Cq9Odmfl5WA==$9Dgl0ZRoCi..
which has the encoder ID),
Nidam will use the encoder specified in this property to resolve it during authentication:
custom:
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.
π CORS URL Configurationβ
Since this will be accessed through the browser, we must provide allowed origins for CORS configuration. Here, the SPA is allowed both directly and through the reverse proxy:
custom:
allowed-cors-uri:
- http://localhost:4001
- http://127.0.0.1:4001
- http://localhost:7080
- http://127.0.0.1:7080
This is the foundation for user storage that Nidam rests on. You're free to use any SQL database and version. You can also switch to a NoSQL database, but you'll have to change the source code yourself for now (MongoDB support is planned).
π Authenticating Users: Authorization Serverβ
This service is responsible for authenticating usersβthis is where users enter their email and password to
access your application. It requires access to the identity_hub
database to authenticate users, so database
credentials and password encoders from the Registration Service are carried over here.
Users are presented with a formβa custom page where you can easily apply your own branding (CSS, images).
This service, aptly named Token Generator, will generate a token that authorizes users to access your protected backend.
For this to work, we need a .jks
file that holds a private key.
This is a requirement, and you should use your OWNβdo not use the provided one in production.
The .jks
file needs to be placed in src/main/resources/
. We supply the alias, password, and filename for the service in application.yml
:
keystore:
password: keypass
privateKey: keystore.jks
alias: alias
Generate Your Own Private Key / Java KeyStoreβ
This code repository already contains a keystore.jks
. You can use it for development, but remember to generate your own before going
to production. Open a terminal and execute this command:
keytool -genkeypair -alias alias -keyalg RSA -keypass keypass -keystore keystore.jks -storepass storepass
This will produce a keystore.jks
file. Don't forget to change the alias, keypass, and storepass values.
Token Expirationβ
By default, tokens last 12 hours. To change this, modify the code:
.tokenSettings(TokenSettings.builder()
.accessTokenTimeToLive(Duration.ofHours(24)) // Change duration here
// Or use: Duration.ofMinutes(30) for shorter sessions
I chose not to expose this through application.yml
for the freedom the code provides. If I were to set it using a property
in the YAML file, I would have you enter the duration in seconds, which is more work on your side. Let me know if this should be exposed.
Client Configurationβ
Another property value you MUST change is the client secret. You don't need to concern yourself with what that means; you just need to do the following:
Download Spring CLI, unzip it, navigate to the /bin
folder in the command line, and run:
PS C:\**\spring-3.5.5\bin> .\spring encodepassword secret
{bcrypt}$2a$10$.ld6BfZescPDfVVduvu.6O9.7FLMI64l4PfvnBZJQEBhTLFFbeKei
Supported algorithms: bcrypt (default) and pbkdf2. To use pbkdf2: spring encodepassword -a pbkdf2 mypassword
. Whichever one you use
must be one of the declared password encoders supplied to the Authorization Server service as explained before.
Nidam uses the word 'secret' as a password for the client, but we need to supply its hash in the YAML file. Copy the output of that command and paste it here:
client:
id: client
secret-hash: '{bcrypt}$2a$10$.ld6BfZescPDfVVduvu.6O9.7FLMI64l4PfvnBZJQEBhTLFFbeKei'
internal-identifier: nidam-bff-internal-id
You may want to change the id
of your client also, but for now, keep it as client. If you change it here, you must change it
elsewhereβlet's not complicate things for now. The internal-identifier
can be changed to whatever you want; it's not used by another
repository, so feel free to rename it.
π Reverse Proxy Configurationβ
The reverse proxy's job is very simple. If the context path is:
/react-ui
β redirect to the React SPA/auth
β redirect to the Authorization Server/bff
β redirect to the BFF
Assuming default ports, there's nothing to change here.
π The Backend for Frontend (BFF) Serviceβ
Assuming default ports, only one or two values need changing here. Remember the client password you provided as a hash in the Token Generator service:
client:
id: client
secret-hash: '{bcrypt}$2a$10$.ld6BfZescPDfVVduvu.6O9.7FLMI64l4PfvnBZJQEBhTLFFbeKei'
internal-identifier: nidam-bff-internal-id
Here in the BFF, you provide the raw password that results in the previous hashβin our case, 'secret'. If you changed the client ID in the auth server, change it here too:
client-id: client
client-secret: secret
That's all you need to concern yourself with.
Here's a summary of what the BFF does:
- SPA calls BFF to initiate login flow
- SPA calls BFF to initiate logout flow
- BFF saves the issued token, creates a session, and associates it with the token, saving the session in an HTTP-only
SESSION
cookie - SPA calls the BFF for protected backend (Resource Server); the BFF reads the session cookie, gets the token, calls the Resource Server, and returns the response to the SPAβwith the SPA completely unaware of these details
π Where Your Code Lives: The Resource Server (Called Nidam)β
This is where you write your backend code. Things to change include the client ID if previously changed:
audience: client
The Resource Server exposes a public endpoint /me
to be called by the SPA. The JSON returned is what the SPA uses to decide if the user
is authenticated or not.
If the user is unauthenticated, it returns:
{
"username": "",
"email": "",
"authorities": [],
"exp": 9223372036854776000
}
If the user is logged in, the returned object will look like:
{
"username": "mehdi@nidam.com",
"email": "mehdi@nidam.com",
"authorities": [
"manage-users",
"manage-projects"
],
"exp": 1757635995
}
The SPA bases its UI authentication logic on this response (showing the authenticated or unauthenticated view). This is also how the SPA gets the user's authorities for authorization purposes (conditional UI element rendering).
I will provide the Resource Server in Jakarta EE as soon as possible, so if you're developing a Jakarta EE backend, you can use the four services made with Spring and write your Jakarta EE backend without bothering with Spring. In fact, the Resource Server can be anything: .NET, Node.js, Rust, Go... . I will try to provide as many variants of the Resource Server as I can in future versions.
π¨ The SPAβ
Obviously, you'll be using your own here, but the logic is simple. You need to supply:
-
Registration backend URL
Nidam Registration Service expects this JSON format:
Without Google reCAPTCHA:
POST "/register"
const user = { email: '', password: ''}
With Google reCAPTCHA:
POST "/registerCaptcha"
const user = { email: '', password: '', recaptchaKey: '' }
Google reCAPTCHA support in Registration Service is built in (click here). Nidam SPA uses the reCAPTCHA endpoint by default.
-
Login URL
This is the reverse proxy URL +
/bff/oauth2/authorization/token-generator
This initiates the OAuth 2.0 login flow.To Devs with OAuth 2 experiencetoken-generator is the registration ID used by Nidam, specifically the BFF.
-
Resource Server URL
This is the reverse proxy URL +
/bff/api
which calls the protected backend. -
Logout URL
This is the reverse proxy URL +
/bff/logout
which calls the BFF and initiates the OAuth 2.0 logout flow.
REACT_APP_BACKEND_REGISTRATION_URL=http://localhost:4000/
REACT_APP_BACKEND_RESOURCE_URL=http://localhost:7080/bff/api
REACT_APP_LOGIN_URL=http://localhost:7080/bff/oauth2/authorization/token-generator
This means you can use your own SPA from the startβno need to use Nidam SPA.
Redirection Featureβ
Nidam supports dynamic redirection for login and logout. Click here to see how.
Your Own Brandingβ
Customizing the login page to match your branding can be found here.
Of interest here is the class nidam/tokengenerator/service/JpaUserDetailsService.java
. If you're using a NoSQL database, you must
change its code so it loads the right implementation of UserDetails
if necessary. If you're using an SQL
database (with Nidam's JPA/DB structure intact), this should be of no concern to you.