Skip to content

Latest commit

 

History

History
250 lines (174 loc) · 6.67 KB

File metadata and controls

250 lines (174 loc) · 6.67 KB

Spring Boot + Keycloak BFF (Backend-for-Frontend)

📚 Full tutorial: Read the step-by-step guide here →
https://natasatm.netlify.app/articles/nextjs-keycloak-spring-boot-bff

This repository demonstrates a Spring Boot 3 Backend-for-Frontend (BFF) secured with Keycloak (OIDC).
It exposes protected API routes that validate JWT tokens issued by Keycloak and enforce role-based access control.

  • 🔐 JWT validation against Keycloak issuer
  • 👥 Role-based endpoints (USER and ADMIN)
  • 🚧 Public vs protected API routes
  • 🤝 Designed to pair with the Next.js + NextAuth frontend

Table of contents


Overview

This BFF sits between your frontend and downstream services.
Tokens are validated server-side against Keycloak. Role-based claims are read from realm_access.roles.

Example flow:

  1. User logs in with Keycloak through the frontend
  2. Frontend calls BFF routes (/api/me, /api/admin/only, etc.)
  3. BFF validates the token and either allows or denies access

Tech stack

  • Java 21
  • Spring Boot 3.x
  • Spring Security (OAuth2 Resource Server)
  • Maven build system

Project structure

src/
  main/
    java/com/natasatm/authdemo/
      api/
        AdminController.java    # ADMIN role protected endpoints
        MeController.java       # User info + public ping endpoint
      config/
        JwtRolesConfig.java     # JWT role extraction configuration
        SecurityConfig.java     # Security and CORS configuration
      AuthDemoApiApplication.java # Main Spring Boot application
    resources/
      application.yml           # Application configuration

Quick start

Prerequisites

  • Java 21 and Maven
  • Keycloak running (see frontend repo for Docker setup)

Note: Keycloak and Mailpit are configured in the frontend repository.
Run the Docker Compose setup from there first before starting this backend.

1. Clone the repository

git clone https://github.com/NatasaTM/springboot-keycloak-bff.git
cd springboot-keycloak-bff

2. Set environment variables

export KC_ISSUER_URI=http://localhost:8080/realms/demo
export ALLOWED_ORIGINS=http://localhost:3000

Or create a .env file if you're using a tool like direnv.

3. Run the application

mvn spring-boot:run

The API will be available at http://localhost:8082.


Environment variables

Variable Description Example
KC_ISSUER_URI Keycloak realm issuer URL http://localhost:8080/realms/demo
ALLOWED_ORIGINS CORS allowed origins (comma-separated) http://localhost:3000

API endpoints

Public endpoints

  • GET /api/public/ping
    No authentication required
    Returns: {"status": "ok"}

Protected endpoints (require valid JWT)

  • GET /api/me
    Returns user information and roles
    Example response:

    {
      "sub": "f12c3d45-6789-0123-4567-89abcdef0123",
      "email": "demo@demo.test",
      "preferred_username": "demo@demo.test",
      "issuedAt": "2024-01-15T10:30:00Z",
      "expiresAt": "2024-01-15T11:30:00Z",
      "roles": ["USER", "ADMIN"]
    }
  • GET /api/admin/only
    Requires ADMIN role
    Returns: "ok - admin"

Health check endpoints

  • GET /actuator/health - Application health status
  • GET /actuator/info - Application information

How it works

JWT validation

Spring Security validates incoming JWT tokens against the Keycloak issuer configured in KC_ISSUER_URI. The validation includes:

  • Token signature verification
  • Token expiration check
  • Issuer validation

Role extraction

Roles are extracted from the realm_access.roles claim in the JWT token and mapped to Spring Security authorities with the ROLE_ prefix:

{
  "realm_access": {
    "roles": ["USER", "ADMIN"]
  }
}

These become ROLE_USER and ROLE_ADMIN in Spring Security.

Security configuration

The security configuration (SecurityConfig.java) defines:

  • Public endpoints that don't require authentication
  • CORS configuration for frontend communication
  • JWT token validation settings
  • Role-based access control rules

Deployment notes

Local development

  1. Make sure Keycloak is running (use Docker Compose from the frontend repo)
  2. Configure environment variables
  3. Run with mvn spring-boot:run

Production deployment

When deploying to production:

  • Use HTTPS for both Keycloak and this backend
  • Update KC_ISSUER_URI to point to your production Keycloak instance
  • Configure ALLOWED_ORIGINS to match your production frontend URL
  • Use environment variables provided by your hosting platform (Render, Railway, Heroku, etc.)
  • Consider using an external database for Keycloak instead of the development setup
  • Enable proper logging and monitoring

Example deployment on Render

  1. Create a new Web Service
  2. Connect your GitHub repository
  3. Set build command: mvn clean package -DskipTests
  4. Set start command: java -jar target/*.jar
  5. Add environment variables in the Render dashboard
  6. Deploy

Useful links


Troubleshooting

401 Unauthorized

  • Check that the JWT token is valid and not expired
  • Verify KC_ISSUER_URI matches your Keycloak realm URL
  • Ensure the token was issued by the correct Keycloak instance

403 Forbidden

  • Verify the user has the required role (USER or ADMIN)
  • Check that roles are correctly configured in Keycloak
  • Inspect the JWT token at https://jwt.io to see the realm_access.roles claim

CORS errors

  • Update ALLOWED_ORIGINS to include your frontend URL
  • Make sure the frontend URL matches exactly (including protocol and port)

License

MIT © 2025 Natasa Todorov Markovic
Feel free to fork and adapt.