Skip to main content

Command Palette

Search for a command to run...

๐Ÿš€ Implementing Secure Okta SSO in Spring Boot with Role-Based Access, JWT, Docker, and Terraform

"Securing Spring Boot with Okta SSO, JWT, and Role-Based Access โ€” From Setup to Deployment"

Published
โ€ข5 min read
P

๐Ÿ‘จโ€๐Ÿ’ป I'm Praveen Gupta, a Senior Backend Engineer with over 10+ years of experience in designing scalable backend systems using Java, Spring Boot, Microservices, and AWS Cloud. I specialize in building cloud-native applications, integrating DevOps practices, and mentoring teams in writing clean, production-grade code. I created this blog to share real-world backend architecture tips, Spring Boot patterns, and practical coding solutions that help developers grow faster.

In this guide, youโ€™ll learn how to implement Single Sign-On (SSO) with Okta โ€” a secure and centralized authentication method where a single set of credentials grants access to multiple applications. Instead of forcing users to log in separately to each service, SSO authenticates them once through a trusted Identity Provider (IdP) like Okta and then issues tokens that allow seamless access to other connected systems. This improves user experience, reduces password fatigue, and strengthens security by enforcing centralized policies like MFA (Multi-Factor Authentication).

Weโ€™ll protect your Spring Boot APIs with JWT-based authorization, so every request is verified against a digitally signed token issued by Okta. This ensures that not only is the user authenticated, but also authorized to perform specific actions based on their roles or scopes.

For deployment, weโ€™ll use Docker to package the application for portability, Terraform to provision and manage infrastructure on AWS, and GitHub Actions to automate CI/CD pipelines.

The implementation will be production-grade โ€” using Java 21 for the latest performance and language features, .properties configuration for clarity and maintainability, and role-based security to precisely control access to APIs.

With this approach, youโ€™ll end up with a secure, scalable, and cloud-ready SSO-enabled Spring Boot application that can be reused across projects and easily integrated into enterprise ecosystems.


๐Ÿ” Goal of This Project

We aim to secure a Spring Boot application using:

  • โœ… Okta SSO (OAuth2 + OIDC)

  • ๐Ÿ” JWT access tokens

  • ๐Ÿ‘ฅ Role-based authorization

  • ๐Ÿ” Token expiration & re-signing

  • ๐Ÿณ Docker for packaging

  • โ˜๏ธ Terraform for AWS hosting

  • ๐Ÿ” GitHub Actions for CI/CD

This architecture supports SSO login, fine-grained access control, and token lifecycle management.


โœ… Step 1: Register Application in Okta

  1. Sign up at https://developer.okta.com

  2. Create a new application:

    • Go to Applications > Create App Integration

    • Choose OIDC - Web Application

    • Set redirect URI to: http://localhost:8080/login/oauth2/code/okta

  3. Save the Client ID and Client Secret

  4. Under Security > API > Authorization Servers, configure custom claims:

    • Add "groups" or "roles" to the token payload

    • This enables Spring to apply role-based access control


โš™๏ธ Step 2: Spring Boot Configuration

Use application.properties for a cleaner and environment-friendly setup.

spring.security.oauth2.client.registration.okta.client-id=...
spring.security.oauth2.client.registration.okta.client-secret=...
spring.security.oauth2.client.registration.okta.scope=openid,profile,email
spring.security.oauth2.client.provider.okta.issuer-uri=https://dev-xxxx.okta.com/oauth2/default
spring.security.oauth2.resourceserver.jwt.issuer-uri=https://dev-xxxx.okta.com/oauth2/default
spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://dev-xxxx.okta.com/oauth2/default/v1/keys
token.validity.seconds=3600

๐Ÿ” Step 3: Role-Based Controller Setup

Using Spring annotations like @PreAuthorize, you can easily enforce access rules.

@GetMapping("/user")
@PreAuthorize("hasAuthority('SCOPE_profile')")
public Map<String, Object> getUser(@AuthenticationPrincipal OidcUser user) {
    return user.getClaims();
}

@GetMapping("/admin")
@PreAuthorize("hasRole('ADMIN')")
public String adminPanel() {
    return "Welcome, Admin!";
}
  • ๐Ÿ” User endpoint is accessible to anyone with the profile scope

  • ๐Ÿ”’ Admin endpoint is accessible only to users with the ADMIN role


๐Ÿ›ก Step 4: SecurityConfig + Token Validation

Hereโ€™s how we configure Spring Security to use Okta JWT tokens and enforce method security:

@EnableMethodSecurity
public class SecurityConfig {
  @Bean
  public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
      .authorizeHttpRequests(auth -> auth
        .requestMatchers("/", "/error").permitAll()
        .anyRequest().authenticated()
      )
      .oauth2Login().and()
      .oauth2ResourceServer().jwt();
    return http.build();
  }
}

๐Ÿ” JWT Expiration Check (Optional)

public boolean isTokenExpired(String jwt) {
  SignedJWT signedJWT = SignedJWT.parse(jwt);
  Date expiry = signedJWT.getJWTClaimsSet().getExpirationTime();
  return expiry.before(Date.from(Instant.now()));
}

โœ… Built-in expiration is automatically enforced by Spring. This utility is useful for debugging or custom token inspection.


๐Ÿ” Step 5: Token Re-signing / Refresh Flow

What Happens When the Token Expires?

  • When the access_token expires, the app uses the refresh_token to get a new token from Okta.

  • Use the /token endpoint:

      POST /oauth2/default/v1/token
      grant_type=refresh_token
      refresh_token=...
    

Want to Handle This In-House?

You can run your own Spring Authorization Server to issue, re-sign, and rotate JWT tokens internally using asymmetric keys.


๐Ÿณ Step 6: Dockerfile for Deployment

FROM eclipse-temurin:21-jdk-alpine
COPY target/*.jar app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
  • โœ… Small image

  • โœ… Java 21 support

  • โœ… Runs anywhere (local, cloud, CI/CD)


โ˜๏ธ Step 7: Terraform + AWS EC2

Provision AWS infra with Terraform to host your app.

resource "aws_instance" "spring_app" {
  ami           = "ami-0c02fb55956c7d316"
  instance_type = "t3.micro"
  ...
}
  • Installs Docker

  • Pulls app image from Docker Hub

  • Runs container on port 443 with HTTPS

  • Configures the security group to allow HTTPS traffic


๐Ÿ”„ Step 8: GitHub Actions for CI/CD

- name: Build & Push Docker image
  run: |
    docker build -t your-dockerhub/okta-sso-app .
    docker push your-dockerhub/okta-sso-app

Add DOCKER_USERNAME and DOCKER_PASSWORD to GitHub Secrets.

โœ… Push to main branch โ†’ App automatically builds and deploys!


๐Ÿงช Testing the Workflow

  1. Navigate to / โ†’ You'll be redirected to Okta login

  2. Log in โ†’ You'll be redirected back with the JWT token

  3. Visit /user โ†’ See your token claims

  4. Visit /admin โ†’ Only works if you have the ADMIN role


๐Ÿ›ก๏ธ Security Best Practices

  • โœ… Always use HTTPS (e.g., via NGINX or Load Balancer)

  • โœ… Set short expiration times on tokens (e.g., 1 hour)

  • โœ… Rotate signing keys frequently (use JWKs)

  • โœ… Store refresh_token securely

  • โœ… Validate audience (aud) and issuer (iss) in JWT


๐Ÿ”— GitHub Repository

๐Ÿ‘‰ https://github.com/praveennic17/okta-sso-spring-boot-v1

You can deploy it using:

  • Docker locally

  • AWS EC2 via Terraform

  • GitHub Actions CI/CD

  • Okta developer account for free auth


๐Ÿ“Œ Whatโ€™s Next?

In the next article, weโ€™ll dive deeper into how JWT works โ€” breaking down its structure (Header, Payload, Signature), how itโ€™s generated, signed, and validated, and common pitfalls to avoid when using JWT in real-world applications.


๐Ÿ’ฌ Feedback?

Found this useful?
Leave a comment or connect with me on LinkedIn.