This project demonstrates a secure authentication flow using Keycloak for user authentication and built-in OTP (One-Time Password) for two-factor authentication (2FA).
- Access:
http://localhost:3000
- App detects the user is not authenticated
- Displays "Login" button
- Clicks "Login" button
- Frontend redirects to Keycloak at
http://localhost:8080
- Keycloak prompts for credentials
- User enters username and password
- Keycloak validates the credentials
- First-time users:
- Keycloak shows a QR code
- User scans it using Google Authenticator, Authy, or similar
- User enters the initial OTP to complete setup
- Returning users:
- Keycloak prompts for a 6-digit OTP code
- User enters code from their authenticator app
- Keycloak validates OTP
- If valid:
- Issues JWT access and refresh tokens
- Redirects user back to the frontend (
http://localhost:3000
) - Frontend stores tokens and updates the UI
- Authenticated users can access protected routes (e.g.
/secure
) - Frontend sends JWT in API request headers
- Protected content is fetched and displayed
- User clicks "Logout"
- Frontend triggers logout via Keycloak
- Keycloak clears session and redirects to home
- React +
react-router-dom
for routing @react-keycloak/web
for Keycloak integration- Public and protected routes
- Token handling managed by Keycloak adapter
- Manages users, logins, and OTP
- Issues JWT tokens
- Stores user data in PostgreSQL
- Configured with custom realm and client
- Stores Keycloak configuration
- Persists user accounts and OTP metadata
- Docker and Docker Compose
- Used for local development and testing
- Authenticator App:
- Google Authenticator
- Authy
- Any TOTP-compatible app
- Realm:
test-realm
- Client:
frontend-app
- Authentication Flow:
browser with 2fa
- Valid Redirect URIs:
http://localhost:3000/*
- Web Origins:
http://localhost:3000
- Keycloak settings in
keycloak.js
- Configure protected routes and token handling
- Update Keycloak config in the frontend.
- Use Docker Compose to run:
docker-compose up --build
-
Open your browser and go to:
http://localhost:8080/admin -
Login with:
- Username:
admin
- Password:
admin
- Username:
- Hover over the "Master" dropdown in the top-left corner.
- Click "Create Realm".
- Set:
- Name:
test-realm
- Name:
- Click "Create".
- In the left sidebar, click "Clients".
- Click "Create client".
- Client ID:
frontend-app
- Client Type:
OpenID Connect
- Click Next.
- Client Authentication:
OFF
(turn the switch off) - Authorization:
OFF
- Click Next.
- Valid Redirect URIs:
http://localhost:3000/*
- Web Origins:
http://localhost:3000
- Click Save.
- Stay in the client settings for
frontend-app
. - Find the section "Valid post logout redirect URIs".
- Add:
/
- Click Save.
- Click "Users" in the left sidebar.
- Click "Add user".
- Fill in:
- Username:
testuser
- Email:
[email protected]
(optional) - First Name:
Test
(optional) - Last Name:
User
(optional)
- Username:
- Click Create.
- Go to the "Credentials" tab.
- Click "Set password".
- Enter:
- Password:
testpass
- Temporary:
YES
- Password:
- Click Save.
- Confirm by clicking "Save password".
- Frontend app to authenticate via Keycloak
- Proper redirects after login/logout
- Go to: http://localhost:8080/admin
- Login using admin credentials.
- Select the realm:
test-realm
.
- In the left sidebar, go to Authentication.
- Click on the Flows tab.
- Click Create flow.
- Set:
- Name:
browser with 2fa
- Name:
- Click Create.
-
With your new flow selected, click Add step.
-
Select Cookie.
-
Set Requirement to
ALTERNATIVE
. -
Click Add sub-flow.
- Name:
Forms
- Flow Type:
generic
- Requirement:
ALTERNATIVE
- Name:
-
Click the + icon next to the newly created Forms sub-flow to expand it.
-
Click Add step:
- Select:
Username Password Form
- Requirement:
REQUIRED
- Select:
-
Click Add step again:
- Select:
OTP Form
- Requirement:
REQUIRED
- Select:
- On the same Flows page, click the Actions dropdown.
- Select Bind flow.
- Choose Browser flow.
- Save/Bind the flow.
Your browser with 2fa
flow should look like:
browser with 2fa
├── Cookie (ALTERNATIVE)
└── Forms (ALTERNATIVE)
├── Username Password Form (REQUIRED)
└── OTP Form (REQUIRED)
- Go to: http://localhost:3000
- Click Login.
- Enter username/password.
- A QR code will be displayed.
- Scan the code using Google Authenticator or Authy.
- Enter the TOTP code shown in your app.
- You will be logged in.
- Go to: http://localhost:3000
- Click Login.
- Enter username/password.
- Enter the code from your authenticator app.
- You will be logged in.
- Google Authenticator
- Authy
- Any TOTP-compatible authenticator app