Skip to main content

Make It Yours

There are two main parts that you can and should customize:

  • application.yml for Spring services and .env for the SPA
  • keystore.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.

user table authorities table join table

The authorities value is very important. It's supplied to the Registration Service in application.yml:

Authorities Configuration
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:

Password Encoders
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:

Bcrypt Password Encoder Only
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:

Password Encoder for Hashes Without ID
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:

CORS Allowed Origins
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.

Production Requirement

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:

.jks File Configuration
keystore:
password: keypass
privateKey: keystore.jks
alias: alias
info

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:

token-generator/.../SecurityConfigStaticKey.java
.tokenSettings(TokenSettings.builder()
.accessTokenTimeToLive(Duration.ofHours(24)) // Change duration here
// Or use: Duration.ofMinutes(30) for shorter sessions
Note

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:

Paste your password hash as the value for secret-hash inside the quotes
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:

From 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:

BFF Client Values
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:

Resource Server Client ID
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:

Unauthenticated State
{
"username": "",
"email": "",
"authorities": [],
"exp": 9223372036854776000
}

If the user is logged in, the returned object will look like:

Authenticated State
{
"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).

Note to Jakarta EE and Non-Java Developers

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 experience

    token-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.

Usage in Nidam SPA
.env
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.

Note to NoSQL Users

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.