June 13, 2025

๐Ÿงต Mastering Singleton Pattern in Java: volatile, synchronized, Spring Bean Scopes & Java 25 Best Practices

๐Ÿง  What is Singleton?

A Singleton ensures only one instance of a class is created and provides a global access point to it.

This is useful for:

  • Configuration classes

  • Logger objects

  • Database connection managers

  • Caching systems


๐Ÿ›‘ Problem: Thread-Unsafe Lazy Singleton

public class Singleton {
    private static Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton(); // ❌ Thread unsafe
        }
        return instance;
    }
}

This code may create multiple instances in a multithreaded environment.


✅ Proper Thread-Safe Singleton with volatile + synchronized

public class Singleton {

    private static volatile Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

⚙️ Modern Singleton Alternatives

๐Ÿ”น Static Holder Pattern

public class Singleton {
    private Singleton() {}
    private static class Holder {
        private static final Singleton INSTANCE = new Singleton();
    }
    public static Singleton getInstance() {
        return Holder.INSTANCE;
    }
}

๐Ÿ”น Enum-based Singleton

public enum Singleton {
    INSTANCE;
}

๐ŸŒฟ Singleton in Spring Framework

Spring beans are Singleton by default, meaning:

Only one instance of the bean is created per Spring container.

✅ Declaring a Singleton Bean (default)

@Component
public class AppConfig {
    // default scope is Singleton
}

or explicitly:

@Component
@Scope("singleton")
public class AppConfig {
}

๐Ÿ”„ Changing Bean Scope in Spring

You can control a bean’s scope using the @Scope annotation.

Available Scopes in Spring (Core)

Scope Description
singleton One shared instance per Spring context (default)
prototype A new instance is created every time it's requested
request One instance per HTTP request (Web only)
session One instance per HTTP session (Web only)
application One instance per ServletContext (Web only)
websocket One instance per WebSocket session

๐Ÿ”ง How to Change Bean Scope

@Component
@Scope("prototype")
public class ReportGenerator {
    // A new instance is returned every time it's injected
}

Or using XML (for older Spring):

<bean id="myBean" class="com.example.MyBean" scope="prototype"/>

๐Ÿงช How to Control and Verify Scope

Example Test Class:

@SpringBootTest
public class ScopeTest {

    @Autowired
    private ApplicationContext context;

    @Test
    void testScope() {
        MyBean b1 = context.getBean(MyBean.class);
        MyBean b2 = context.getBean(MyBean.class);

        System.out.println(b1 == b2 ? "Singleton" : "Prototype");
    }
}

๐Ÿ’Ž Java 25 Best Practices for Singleton

✅ Use volatile in lazy initialization
✅ Use @Scope("singleton") in Spring for explicit intent
✅ Use enum to prevent reflection/cloning
✅ Avoid heavy logic in constructor
✅ Override readResolve() if serializing
✅ Use @ThreadSafe for clarity
✅ Use JMH to benchmark Singleton performance
✅ Prefer DI-managed beans (Spring, Micronaut, etc.)
✅ Protect against classloader issues in plugins


๐Ÿ”š Conclusion

  • Use volatile and synchronized together in double-checked locking.

  • Use static inner class or enum for better control.

  • In Spring, prefer letting the container manage Singleton scope.

  • Change scope using @Scope, depending on your app needs.


✨ Summary Table

Singleton Pattern Thread-safe Lazy Init Recommended
static instance
synchronized method ⚠️
volatile + sync
Static holder ✅✅
Enum ✅✅ ✅✅✅
Spring Singleton Bean ✅✅✅

Would you like this exported as a Markdown file, HTML, or copy-ready for Medium/Dev.to?

June 12, 2025

Understanding authSession.setAction(AUTHENTICATE) and Related Settings in Keycloak Login Flows

When customizing login flows in Keycloak—especially during first login with an identity provider (IdP)—you often interact with the AuthenticationSessionModel and AuthenticatedClientSessionModel. If you’ve looked at lines like the following and wondered what they do or why they’re necessary, this blog is for you:

authSession.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
authSession.setClientNote(OIDCLoginProtocol.ISSUER, Urls.realmIssuer(session.getContext().getUri().getBaseUri(), realm.getName()));
authSession.setClientNote(OIDCLoginProtocol.SCOPE_PARAM, "openid");
authSession.setAction(AuthenticatedClientSessionModel.Action.AUTHENTICATE.name());

๐ŸŽฏ Problem Statement

In a custom login flow, particularly when modifying the first broker login flow, missing or incorrect session attributes can result in:

  • invalid_request or invalid_signature errors

  • missing id_tokens

  • broken post-login steps like account linking or consent pages

  • failure to issue access or refresh tokens

To ensure smooth interoperability between Keycloak and the OIDC protocol, it's essential to explicitly configure the authSession.


๐Ÿงช What Each Line Does and Why It Matters

1️⃣ authSession.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);

  • Purpose: Tells Keycloak that the current session is using the openid-connect protocol.

  • Why it's important: Without it, Keycloak might not route the request properly or issue OIDC-compliant tokens.


2️⃣ authSession.setClientNote(OIDCLoginProtocol.ISSUER, <issuer-url>);

  • Purpose: Sets the issuer for the session, which is later embedded in the id_token.

  • Why it's important: If this doesn’t match the value expected by the client, token verification will fail with an "invalid issuer" error.


3️⃣ authSession.setClientNote(OIDCLoginProtocol.SCOPE_PARAM, "openid");

  • Purpose: Specifies the OAuth2/OIDC scopes requested by the client.

  • Why it's important: The "openid" scope is required to receive an id_token. If omitted, your application won’t get identity claims.


4️⃣ authSession.setAction(AUTHENTICATE);

  • Purpose: Sets the session's current action to AUTHENTICATE, signaling Keycloak that the user is in the authentication step.

  • Why it's important:

    • Drives what Keycloak will do next (e.g., show login form, redirect to consent).

    • Affects what happens after authentication—like whether required actions or token exchange steps will run.

    • Without it, the flow can end prematurely or fail entirely.


๐Ÿงพ Available Actions in AuthenticatedClientSessionModel.Action

These enum values define what stage the user is currently in within the Keycloak login or token flow:

Action Description
AUTHENTICATE User is currently authenticating (e.g., login form, social login)
LOGGED_IN Authentication is completed successfully
REQUIRED_ACTIONS User must perform additional steps (verify email, update password, etc.)
CODE_TO_TOKEN The client is exchanging an authorization code for tokens (OAuth2 Code Flow)
OAUTH_GRANT The user is granting consent to the client for requested scopes
REGISTER User is undergoing the registration flow

These values control what happens next in the flow, which UI screens are shown, and which server-side logic gets triggered.


๐Ÿงฉ Where You Typically Use This

These session settings are commonly found in:

  • IdpCreateUserIfUniqueAuthenticator (default first-login logic)

  • Your custom Authenticator or AuthenticatorFactory when extending login flow

  • SPIs that handle custom logic during IdP login or user account creation


✅ Best Practices

  • Always set the protocol, scope, and issuer for custom login flows.

  • Set the action to match the current step (AUTHENTICATE, REGISTER, etc.).

  • Ensure you do this before token issuance or response handling steps.


๐Ÿšซ What Happens If You Skip These

Setting Without It...
setProtocol(...) Flow might not work; tokens might not be generated.
setClientNote(ISSUER) id_token may have wrong issuer → validation fails.
setClientNote(SCOPE_PARAM) No id_token, breaking OIDC login.
setAction(AUTHENTICATE) Flow breaks midway or doesn't trigger post-login handlers.

๐Ÿง  Conclusion

Customizing Keycloak login flows is powerful but requires careful handling of session metadata. These authSession configurations are not optional—they are critical building blocks for a stable and secure authentication experience.

If you're implementing a custom Authenticator or enhancing the first-broker-login flow, make sure to explicitly set these session details to avoid unpredictable errors and ensure a smooth experience for both users and client applications.