July 1, 2025

๐Ÿ” OAuth 2.0 Overview: Introduction to Standards Protocol Flows and Integration with Keycloak

OAuth 2.0 is the gold standard for delegated authorization. It provides multiple flows to suit different application types and trust levels. This guide dives deep into:

  • Recap the AuthN and AuthZ

  • OAuth 2.0 Flows: Client Credentials, Authorization Code, and Authorization Code with PKCE

  • Client types: Confidential and Public

  • Sequence diagrams for each flow (compatible with https://www.websequencediagram.com)

  • Keycloak configuration examples for each flow

  • curl commands to request tokens from Keycloak

  • Security concerns, best practices, and when to use what

๐Ÿ” What is Authentication and Authorization?

ConceptMeaningExample
AuthenticationVerifying who you are.Logging in with username/password, or Google login to prove your identity.
AuthorizationVerifying what you can do or access after authentication.Can this user access /admin page or update a record after logging in?

๐Ÿงญ Purpose and Use

AspectAuthenticationAuthorization
GoalProve identityControl access to resources
Happens when?First stepAfter authentication
Protocol ExamplesOpenID Connect (on top of OAuth 2)OAuth 2.0 (Authorization Framework)
Who uses the data?Login system (e.g., Keycloak)Backend/API/gateway with access policies
Typical DataUsername, password, biometricsRoles, permissions, scopes

๐Ÿ› ️ Which Protocol Does What?

Flow or ProtocolUsed ForHandles Authentication?Handles Authorization?
OAuth 2.0Delegated access❌ No✅ Yes
OpenID Connect (OIDC)Identity layer on OAuth✅ Yes (who the user is)✅ Sometimes (via scopes/claims)
SAMLEnterprise SSO✅ Yes✅ Yes
Basic Auth / Form LoginSimple login systems✅ Yes❌ No

๐Ÿ”‘ In OAuth 2.0 Context

  • Authentication: Usually handled by OIDC or a login form in the Identity Provider (IdP) like Keycloak.

  • Authorization: Managed through OAuth 2.0 scopes, roles, or resource server policies.

๐Ÿ“˜ 1. What is an OAuth Client?

An OAuth client is an application requesting access to protected resources on a user's behalf or on its own behalf.


๐Ÿ› ️ 2. Client Types: Confidential vs Public

Type Can Store Secrets? Typical Examples
Confidential Yes Server-side apps, CLIs
Public No Mobile apps, SPAs

✅ 3. Client Credentials Flow (Confidential Client)

Use Case: Service-to-service or machine-to-machine communication (no end-user).

๐Ÿงพ Sequence Diagram

title Client Credentials Flow (Confidential Client)

Client->Auth Server: POST /token\nclient_id + client_secret\ngrant_type=client_credentials
Auth Server->Client: 200 OK\naccess_token
Client->Resource Server: GET /protected-resource\nAuthorization: Bearer access_token
Resource Server->Client: 200 OK\nprotected data



๐Ÿ”ง Keycloak Setup

  1. Go to Clients → Create a new client

  2. Client ID: my-service-client

  3. Client Type: Confidential

  4. Enable Service Accounts Enabled

  5. Set credentials and copy client_id & client_secret

  6. Assign appropriate client roles under Service Account Roles

  7. Token Endpoint: https://<keycloak-host>/realms/<realm>/protocol/openid-connect/token

curl -X POST \
  https://<keycloak-host>/realms/<realm>/protocol/openid-connect/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=my-service-client" \
  -d "client_secret=YOUR_CLIENT_SECRET"

๐Ÿ™‹‍♂️ 4. Authorization Code Flow (Confidential Client)

Use Case: Web applications with backend able to keep secrets. Requires user login.

๐Ÿงพ Sequence Diagram

title Authorization Code Flow (Confidential Client)

Client->User: Redirect to Auth Server login
User->Auth Server: Logs in, grants consent Auth Server->Client: Redirect with code Client->Auth Server: POST /token\ncode + client_id + client_secret Auth Server->Client: 200 OK\naccess_token + refresh_token Client->Resource Server: GET /protected-resource\nAuthorization: Bearer access_token Resource Server->Client: 200 OK\nprotected data


๐Ÿ”ง Keycloak Setup

  1. Go to Clients → Create a new client

  2. Client ID: my-web-client

  3. Client Type: Confidential

  4. Root URL: https://your-app.com

  5. Valid Redirect URIs: https://your-app.com/callback

  6. Enable Standard Flow Enabled

  7. Note the token endpoint: https://<keycloak-host>/realms/<realm>/protocol/openid-connect/token

curl -X POST \
  https://<keycloak-host>/realms/<realm>/protocol/openid-connect/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "client_id=my-web-client" \
  -d "client_secret=YOUR_CLIENT_SECRET" \
  -d "code=AUTH_CODE_FROM_CALLBACK" \
  -d "redirect_uri=https://your-app.com/callback"

๐Ÿ“ฑ 5. Authorization Code Flow with PKCE (Public Client)

Use Case: Mobile apps or SPAs where secrets cannot be stored securely.

๐Ÿงพ Sequence Diagram

title Authorization Code Flow with PKCE (Public Client)

Client->Auth Server: Redirect with\ncode_challenge (PKCE)
User->Auth Server: Logs in, grants consent
Auth Server->Client: Redirect with code
Client->Auth Server: POST /token\ncode + code_verifier (PKCE)
Auth Server->Client: 200 OK\naccess_token
Client->Resource Server: GET /protected-resource\nAuthorization: Bearer access_token
Resource Server->Client: 200 OK\nprotected data



๐Ÿ”ง Keycloak Setup

  1. Go to Clients → Create a new client

  2. Client ID: my-spa-client

  3. Client Type: Public

  4. Enable Standard Flow Enabled

  5. Set Valid Redirect URIs (e.g. http://localhost:3000/*)

  6. Enable PKCE (enabled by default from Keycloak 18+)

  7. Do not set client secret (public clients should not use one)

curl -X POST \
  https://<keycloak-host>/realms/<realm>/protocol/openid-connect/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "client_id=my-spa-client" \
  -d "code=AUTH_CODE_FROM_CALLBACK" \
  -d "code_verifier=YOUR_CODE_VERIFIER" \
  -d "redirect_uri=http://localhost:3000/callback"

๐Ÿ›ก️ 6. Security Considerations

Risk Applies To Mitigation
Token theft All flows Use HTTPS, secure storage
Secret leakage Confidential Store secrets in vaults, env vars
Replay attacks Public clients Use PKCE with code_verifier
Authorization code leakage All code flows Use state param + PKCE
Refresh token misuse All code flows Issue only to confidential clients

๐Ÿ† 7. Which Flow to Use When?

Flow Client Type User Involved Use Case
Client Credentials Confidential No M2M, background jobs, microservices
Authorization Code Confidential Yes Web apps with secure backend
Auth Code + PKCE Public Yes SPAs, mobile apps

๐Ÿ“„ 8. Summary Table

Flow Requires Secret Safe for Public Refresh Token PKCE Required
Client Credentials Yes No No No
Authorization Code Yes No Yes No
Auth Code + PKCE No Yes Sometimes Yes

๐ŸŒŸ 9. Best Practices

  • Always use PKCE for mobile/web public clients

  • Use short-lived access tokens and rotating refresh tokens

  • Validate state and nonce to prevent CSRF and replay

  • Use scopes to enforce least privilege


๐Ÿš€ 10. Tools to Visualize Sequence Diagrams

All diagrams here are compatible with https://www.websequencediagram.com. Paste any of them to view and customize.


๐Ÿ“ Final Thoughts

Choosing the right OAuth flow depends on:

  • Whether you're authenticating a user or a service

  • Whether the client is trusted to hold secrets

  • Whether the platform supports secure storage

Use this guide as a blueprint to implement secure OAuth 2.0 integrations confidently using Keycloak as your Identity Provider.

June 30, 2025

๐Ÿ”️ Finding a Peak Element in an Array — Efficient Solutions in Java (with Java 21 Best Practices)

๐Ÿ“Œ Problem Statement

You are given an integer array nums. Your task is to find a peak element and return its index.

A peak element is one that is:

  • strictly greater than its neighbors.

  • i.e., nums[i - 1] < nums[i] > nums[i + 1].

Special Notes:

  • You only need to return any one peak — not all.

  • The array may have multiple peaks.

  • Assume nums[-1] and nums[n] are -∞ (imaginary values outside the array).


๐Ÿง  Intuition — What Is the Question Really Asking?

Imagine you're walking along a mountain trail, and someone asks:

“Can you find a point where you're standing on a hilltop, higher than both the person behind you and ahead of you?”

You don’t need the highest mountain, just any place where you're on top compared to your neighbors.

Why is this interesting?

Because instead of checking every point on the trail, you can cleverly skip sections using the idea that:

  • If you're going uphill, a peak must lie ahead.

  • If you're going downhill, a peak must lie behind or at your current position.

This observation is perfect for binary search — we can reduce our search space by half each time.


๐Ÿงช Example

Given:

int[] nums = {1, 2, 3, 1};
  • At index 2, nums[2] = 3, and 3 > 2 and 3 > 1 → so index 2 is a peak.


๐Ÿšถ‍♂️ Approach 1: Brute Force (Linear Scan)

Go element by element and check if it's greater than its neighbors.

public static int findPeakLinear(int[] nums) {
    for (int i = 0; i < nums.length; i++) {
        boolean leftOk = (i == 0 || nums[i] > nums[i - 1]);
        boolean rightOk = (i == nums.length - 1 || nums[i] > nums[i + 1]);
        if (leftOk && rightOk) return i;
    }
    return -1; // fallback
}

✅ Pros:

  • Very easy to implement

❌ Cons:

  • Time complexity: O(n)

  • Not efficient for large arrays


⚡ Approach 2: Binary Search (Optimal and Recommended)

Use the fact that a peak exists if the slope changes from rising to falling. If nums[mid] < nums[mid + 1], move right. Else, move left.

Java 21 Version

public class PeakFinder {

    public static int findPeakElement(int[] nums) {
        if (nums == null || nums.length == 0)
            throw new IllegalArgumentException("Array must not be null or empty");

        int left = 0, right = nums.length - 1;

        while (left < right) {
            int mid = Math.addExact(left, (right - left) / 2);

            if (nums[mid] < nums[mid + 1]) {
                left = mid + 1; // peak is to the right
            } else {
                right = mid; // peak is to the left or at mid
            }
        }

        return left;
    }
}

⏱️ Time: O(log n)

๐Ÿ“ฆ Space: O(1)

✅ Pros:

  • Very efficient

  • Guarantees a peak due to the problem’s conditions


๐Ÿงฉ Approach 3: Recursive Divide and Conquer

Same logic as binary search, but using recursion:

public class PeakFinder {

    public static int findPeakRecursive(int[] nums) {
        return search(nums, 0, nums.length - 1);
    }

    private static int search(int[] nums, int left, int right) {
        if (left == right) return left;

        int mid = left + (right - left) / 2;

        if (nums[mid] < nums[mid + 1]) {
            return search(nums, mid + 1, right);
        } else {
            return search(nums, left, mid);
        }
    }
}

๐Ÿ“ˆ Real-World Analogy (Peak Hiker)

Think of yourself as a hiker on a trail:

  • When the path is going up, you know a peak is ahead.

  • When the path goes down, the peak was behind or at your feet.

  • If you're already on a peak, stop walking.

Binary search lets you skip large parts of the trail because you're always choosing the direction that guarantees a peak exists.


๐Ÿง  Why Binary Search Works Here

Even though the array is not sorted, you can still apply binary search because:

  • There is always at least one peak.

  • At each step, you can eliminate half the array based on the comparison of nums[mid] and nums[mid+1].


✅ Summary Table

Approach Time Complexity Space Complexity Best Use Case
Linear Scan O(n) O(1) Small inputs or quick demo
Binary Search O(log n) O(1) Optimal, all scenarios ✅
Recursive O(log n) O(log n) When recursion is preferred

๐Ÿ’ก Interview Tip

Even if the array isn't sorted, binary search can still be applied in problems where the structure allows elimination of search space — and this is a perfect example.


๐Ÿ› ️ Extras for Practice

  • Modify to find all peak elements

  • Apply a similar approach for a 2D matrix peak problem

  • Implement in a functional style using Java Streams (advanced)


Would you like this content:

  • Exported as HTML for Blogger?

  • Converted to Markdown for Dev.to or GitHub Pages?

  • Embedded with code playground for interactive testing?

Let me know — I can format it to suit your blog setup!

June 27, 2025

๐ŸŒŸ The Servant Leader Problem – A Modern Corporate Dilemma

“The best leaders are those who serve.”
— Robert Greenleaf, Founder of Servant Leadership Philosophy

In today’s corporate world, leadership is no longer about power—it’s about purpose. The Servant Leader model has gained massive popularity for its people-first approach. But despite its noble intent, servant leadership can backfire if misunderstood or poorly applied.

This blog explores the Servant Leader Problem:
Why does a leadership style built on empathy sometimes fail?
And how can we fix it?


๐Ÿ” What Is Servant Leadership?

Servant Leadership is a leadership philosophy where the leader's main goal is to serve others—employees, customers, and the organization—before themselves.

๐Ÿ”‘ Core Principles:

  • Listening actively

  • Putting others’ needs first

  • Empowering team members

  • Promoting growth and well-being

  • Leading by example, not authority

Think of a team manager who ensures the intern is confident before a big client call, or a CTO who skips credit to highlight her team’s work.


๐Ÿ† Why It Works (When It Works)

Organizations like Southwest Airlines, Starbucks, and Infosys have leveraged servant leadership to:

✅ Build trust and loyalty
✅ Reduce attrition
✅ Drive innovation
✅ Boost morale and collaboration

In Agile environments (Scrum, SAFe), the Scrum Master is designed as a servant leader — someone who clears blockers and enables the team to deliver value.


⚠️ The Servant Leader Problem: When Service Becomes a Setback

๐Ÿ“‰ Problem 1: Loss of Authority

When leaders focus solely on serving, they may fail to set boundaries. Team members may:

  • Take liberties

  • Undervalue the leader’s authority

  • Avoid accountability

๐Ÿ—ฃ “My manager is too soft — nothing happens even if I miss deadlines.”


๐Ÿ˜ฐ Problem 2: Burnout & Emotional Exhaustion

Servant leaders often carry everyone’s burdens:

  • Handling team issues

  • Soothing clients

  • Taking work home

Over time, they become drained, affecting their health and leadership clarity.

๐Ÿ’ฌ “I help everyone, but I’m running on empty.”


๐ŸŒ Problem 3: Decision Paralysis

Trying to involve everyone in every decision can delay action. In high-stakes or fast-paced environments, this leads to:

  • Missed opportunities

  • Poor crisis response

๐Ÿง  “Let’s wait until we hear from the whole team” becomes the default — even when time-sensitive.


๐Ÿง  Root Cause: Misinterpretation of “Service”

Many assume servant leadership means pleasing everyone. In truth, it means serving the mission through the people, not at the cost of results.

Servant leadership ≠ People-pleasing
Servant leadership = People-empowering


✅ Striking the Balance: The Empowered Servant Leader

Great leaders serve without surrendering control. They know:

  • When to step in

  • When to say “No”

  • How to guide without dominating

Trait Unbalanced Servant Empowered Servant Leader
Decision Making Seeks endless consensus Invites input, decides firmly
Accountability Absorbs all blame Shares responsibility
Workload Does everything for others Coaches others to own outcomes
Presence Avoids confrontation Handles tough talks respectfully

๐Ÿ’ผ Real Corporate Example: Ravi, the Tech Lead

Ravi, a tech lead at a SaaS company, followed servant leadership to the letter:

  • Protected juniors from client pressure

  • Volunteered for everyone’s unfinished work

  • Delayed decisions to include every opinion

Result?

  • Team became over-reliant

  • Deliverables slipped

  • Ravi burned out

  • Leadership was reassigned

๐Ÿšจ Intent was good. Execution wasn’t.


๐Ÿ› ️ How to Fix the Servant Leader Problem

1. Lead with Boundaries

“I care about your growth, but we must meet deadlines.”

2. Serve the Mission First

Empower people in a way that aligns with company goals.

3. Balance Empathy with Expectations

Support without compromising accountability.

4. Model Self-Care

Show that leaders also need rest, clarity, and limits.


๐Ÿ’ฌ Final Thought

“You don’t lead by pointing and telling people where to go. You lead by going to that place and making a case.”
— Ken Kesey

Great servant leaders:

  • Empower, not enable

  • Listen, but lead

  • Serve, but also steer

In the corporate world, the servant leader is not the weakest in the room. They’re the strongest — because they lift everyone without falling themselves.


๐Ÿ“Œ Summary (TL;DR):

✅ Servant Leadership Strengths ⚠️ Servant Leader Problems
Builds trust & loyalty Can lose authority
Boosts team performance Risks burnout
Enhances collaboration Slows decisions
Empowers people May lack boundaries

๐Ÿ”‘ Fix: Serve with structure. Lead with empathy — but don’t forget to lead.



June 25, 2025

๐Ÿ”ข Mastering Relative Sorting in Java (With Java 8 Best Practices)

Sorting an array based on another array's order is a popular coding problem seen in interviews and real-world systems where custom sorting logic is required.


๐Ÿงฉ Problem Statement

You're given two arrays:

  • arr1: The array you need to sort.

  • arr2: Specifies the relative ordering of some elements.

๐Ÿ“Œ Sort Rules:

  1. Elements from arr1 that are in arr2 appear first, in the same order as in arr2.

  2. Remaining elements (not in arr2) are sorted in ascending order.


✅ Example

Input:
arr1 = [2,3,1,3,2,4,6,7,9,2,19]
arr2 = [2,1,4,3,9,6]

Output:
[2,2,2,1,4,3,3,9,6,7,19]

๐Ÿงช Approach 1: Counting Sort (Optimal if Range is Known)

✅ Code:

public int[] relativeSortArray(int[] arr1, int[] arr2) {
    int[] count = new int[1001]; // assume elements are in 0–1000 range
    for (int num : arr1) count[num]++;

    int[] result = new int[arr1.length];
    int i = 0;

    for (int num : arr2)
        while (count[num]-- > 0)
            result[i++] = num;

    for (int num = 0; num < count.length; num++)
        while (count[num]-- > 0)
            result[i++] = num;

    return result;
}

✅ When to Use:

  • You know the range of input (e.g., 0 to 1000).

  • Performance is critical (time complexity: O(n + m + k)).

  • Memory usage is acceptable for fixed range.

๐Ÿง  Tips:

  • Preallocate frequency arrays if range is predictable.

  • Avoid using this for values outside a known range (e.g., negative numbers, large integers).


๐ŸŒŸ Approach 2: Java 8 Functional Solution (Elegant & Flexible)

✅ Code:

import java.util.*;
import java.util.stream.Collectors;

public class Solution {
    public int[] relativeSortArray(int[] arr1, int[] arr2) {
        Map<Integer, Integer> indexMap = new HashMap<>();
        for (int i = 0; i < arr2.length; i++) indexMap.put(arr2[i], i);

        List<Integer> list = Arrays.stream(arr1).boxed().collect(Collectors.toList());

        list.sort((a, b) -> {
            if (indexMap.containsKey(a) && indexMap.containsKey(b))
                return Integer.compare(indexMap.get(a), indexMap.get(b));
            else if (indexMap.containsKey(a))
                return -1;
            else if (indexMap.containsKey(b))
                return 1;
            else
                return Integer.compare(a, b);
        });

        return list.stream().mapToInt(Integer::intValue).toArray();
    }
}

✅ When to Use:

  • You want a cleaner, more readable solution.

  • The input range is unknown or unbounded.

  • You’re working in a modern Java codebase that uses Streams and Lambdas.


๐Ÿง  Best Practices & Tips

Practice Tip
๐Ÿ”ข Choose Right Approach Use counting sort for known integer ranges. Use Java 8 functional approach for readability and flexibility.
♻️ Avoid Magic Numbers Use Integer.MAX_VALUE or define range constants instead of hardcoding 1001.
๐Ÿ” Handle Edge Cases Always account for: duplicates, missing values in arr2, or values in arr2 not present in arr1.
⚙️ Immutable Data Prefer working with immutable streams when functional clarity matters.
๐Ÿ”„ Convert Safely Use boxed() and mapToInt() to safely convert between primitives and wrappers.
๐Ÿš€ Optimize for Large Input Counting sort is more performant than stream sorting when input size is large and value range is small.
๐Ÿงช Unit Testing Cover edge cases like arr2 being empty, all values in arr1 being outside arr2, etc.

๐Ÿ“š Summary

Feature Counting Sort Java 8 Functional
Input Range Required ✅ Yes (e.g., 0–1000) ❌ No
Duplicates ✅ Handled ✅ Handled
Readability ❌ Medium ✅ High
Performance ✅ Faster for small range ❌ Slightly Slower
Suitable for Interviews ✅ Yes ✅ Yes (bonus if explained well)

๐Ÿง‘‍๐Ÿ’ป Final Thoughts

Both approaches are valid and useful depending on your context:

  • For interview coding rounds, start with the counting sort for performance, then mention the Java 8 version as a cleaner alternative.

  • For production code, prefer the Java 8 solution unless performance is critical and the input range is tightly controlled.

June 16, 2025

AWS Lambda vs AWS Step Functions: Choosing the Right Serverless Tool

 In the world of serverless computing, two of the most powerful and widely used services offered by AWS are Lambda and Step Functions. While both serve critical roles in modern application development, understanding their strengths, limitations, and when to use each is key to building efficient and scalable systems.


What is AWS Lambda?

AWS Lambda is a compute service that lets you run code without provisioning or managing servers. It executes your code only when needed and scales automatically.

Key Features:

  • Supports multiple programming languages (Node.js, Python, Java, etc.)

  • Triggered by events from AWS services like S3, API Gateway, DynamoDB

  • Ideal for short-lived, stateless functions

  • Pay-per-use billing model (based on number of requests and execution time)

Common Use Cases:

  • Resizing images uploaded to S3

  • Backend APIs

  • Real-time file processing

  • Lightweight ETL jobs


What are AWS Step Functions?

AWS Step Functions is an orchestration service that enables you to coordinate multiple AWS services into serverless workflows. It uses a state machine model to define and manage each step.

Key Features:

  • Define workflows in JSON or YAML

  • Visual workflow builder (Workflow Studio)

  • Built-in error handling, retries, and parallelism

  • Integrates with over 200 AWS services directly

  • Two types: Standard (long-running workflows) and Express (high-throughput, short-lived workflows)

Common Use Cases:

  • Orchestrating microservices

  • Data pipelines

  • Approval workflows

  • Long-running business processes


Lambda vs Step Functions: A Comparison

Feature AWS Lambda AWS Step Functions
Purpose Execute code Orchestrate workflows
Execution Time Limit Up to 15 minutes Up to 1 year (Standard), 5 mins (Express)
State Management Manual Built-in
Error Handling In-code try/catch Declarative Retry/Catch per state
Parallel Execution Manual logic required Built-in Parallel state
Visual Debugging Logs only (CloudWatch) Full execution trace and workflow map
Best For Single, short tasks Coordinating multi-step workflows

When to Use Lambda

Use AWS Lambda when you:

  • Need to perform a single task in response to an event

  • Require fast and lightweight processing

  • Don't need to manage state between executions

  • Want simple, cost-effective compute


When to Use Step Functions

Use AWS Step Functions when you:

  • Need to coordinate multiple AWS services or Lambda functions

  • Require visual monitoring and debugging

  • Want built-in error handling and retry logic

  • Are building long-running or complex workflows


Real-World Example

Scenario: A photo processing pipeline

With Lambda only: You’d need to manage invocation of each processing step (e.g., resizing, watermarking, storing) manually, handle retries and errors in code.

With Step Functions: Each step is defined as a state. You gain clear visibility, parallel processing (e.g., for different sizes), and built-in retries.


Conclusion

Both AWS Lambda and Step Functions are integral to serverless development, but they shine in different areas. For independent, simple functions, Lambda is the go-to choice. For multi-step, error-prone, or complex processes, Step Functions provide powerful orchestration capabilities.

Understanding when to use each will help you design better, more scalable, and maintainable serverless architectures.

AWS Lambda vs AWS Step Functions: Choosing the Right Serverless Tool

In the world of serverless computing, two of the most powerful and widely used services offered by AWS are Lambda and Step Functions. While both serve critical roles in modern application development, understanding their strengths, limitations, and when to use each is key to building efficient and scalable systems.


What is AWS Lambda?

AWS Lambda is a compute service that lets you run code without provisioning or managing servers. It executes your code only when needed and scales automatically.

Key Features:

  • Supports multiple programming languages (Node.js, Python, Java, etc.)

  • Triggered by events from AWS services like S3, API Gateway, DynamoDB

  • Ideal for short-lived, stateless functions

  • Pay-per-use billing model (based on number of requests and execution time)

Common Use Cases:

  • Resizing images uploaded to S3

  • Backend APIs

  • Real-time file processing

  • Lightweight ETL jobs


What are AWS Step Functions?

AWS Step Functions is an orchestration service that enables you to coordinate multiple AWS services into serverless workflows. It uses a state machine model to define and manage each step.

Key Features:

  • Define workflows in JSON or YAML

  • Visual workflow builder (Workflow Studio)

  • Built-in error handling, retries, and parallelism

  • Integrates with over 200 AWS services directly

  • Two types: Standard (long-running workflows) and Express (high-throughput, short-lived workflows)

Common Use Cases:

  • Orchestrating microservices

  • Data pipelines

  • Approval workflows

  • Long-running business processes


Lambda vs Step Functions: A Comparison

Feature AWS Lambda AWS Step Functions
Purpose Execute code Orchestrate workflows
Execution Time Limit Up to 15 minutes Up to 1 year (Standard), 5 mins (Express)
State Management Manual Built-in
Error Handling In-code try/catch Declarative Retry/Catch per state
Parallel Execution Manual logic required Built-in Parallel state
Visual Debugging Logs only (CloudWatch) Full execution trace and workflow map
Best For Single, short tasks Coordinating multi-step workflows

When to Use Lambda

Use AWS Lambda when you:

  • Need to perform a single task in response to an event

  • Require fast and lightweight processing

  • Don't need to manage state between executions

  • Want simple, cost-effective compute


When to Use Step Functions

Use AWS Step Functions when you:

  • Need to coordinate multiple AWS services or Lambda functions

  • Require visual monitoring and debugging

  • Want built-in error handling and retry logic

  • Are building long-running or complex workflows


Real-World Example

Scenario: A photo processing pipeline

With Lambda only: You’d need to manage invocation of each processing step (e.g., resizing, watermarking, storing) manually, handle retries and errors in code.

With Step Functions: Each step is defined as a state. You gain clear visibility, parallel processing (e.g., for different sizes), and built-in retries.


Conclusion

Both AWS Lambda and Step Functions are integral to serverless development, but they shine in different areas. For independent, simple functions, Lambda is the go-to choice. For multi-step, error-prone, or complex processes, Step Functions provide powerful orchestration capabilities.

Understanding when to use each will help you design better, more scalable, and maintainable serverless architectures.

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.

May 19, 2025

Introducing the Smart Federated Identity Hub: Next-Gen Context-Aware SSO with AI-Powered Claim Management

In today’s hyper-connected digital ecosystem, enterprises rely heavily on Single Sign-On (SSO) to streamline user access across multiple applications and services. Tools like Keycloak have become the backbone for identity and access management (IAM), offering seamless authentication and authorization experiences.

However, with great power comes great responsibility. One persistent challenge remains unresolved: How can organizations selectively share user data (claims) with different client applications in a way that respects privacy, regulatory compliance, and business-specific requirements — all without compromising user experience?


The Challenge: Balancing Data Sharing with Privacy and Security

When a user logs in through an identity provider like Keycloak, a set of claims (user attributes such as email, phone number, roles) is sent to the requesting client application. But:

  • Most current systems apply a one-size-fits-all approach, releasing identical claims to all clients.

  • This overexposure increases privacy risks and may violate regulations like GDPR, HIPAA, or India’s DPDP.

  • Different clients (e.g., HR portal vs. Marketing app) often require different subsets of user data.

  • Managing claim configurations manually for dozens or hundreds of clients quickly becomes unsustainable.

  • There’s no dynamic mechanism to factor in contextual signals like user consent, login device, location, or behavioral risk.

As businesses scale, this inefficiency creates serious security vulnerabilities and compliance bottlenecks, limiting the adoption of federated identity solutions in sensitive domains like finance, healthcare, and government.


The Vision: A Smart Federated Identity Hub

Imagine an identity hub that intelligently and dynamically controls which user claims to share with which client — powered by AI and enriched with contextual awareness.

Our proposed solution integrates:

  • Keycloak as the core identity broker

  • Custom extensions (via Keycloak SPI) that trigger an AI-powered decision engine at login

  • Real-time invocation of a GenAI model (GPT-4o mini) that assesses user, client, and contextual data

  • Dynamic claim release tailored to client-specific policies, user consent, and risk signals

  • A Consent Ledger tracking data sharing events for auditing and compliance

  • Use of MCP (Microservice Communication Protocol) for secure downstream propagation of selective claims to partner services

  • Optional Explainability UI to visualize why certain claims were shared or withheld, building trust and transparency


How It Works: Context-Aware Claim Decisions

When a user initiates an SSO login:

  1. Keycloak invokes the AI-driven ClaimsMapper SPI, passing key information about the user, client, login context, and prior consents.

  2. The AI model processes this input, referencing internal policies and learned patterns, and outputs a customized list of claims allowed for release.

  3. Keycloak releases only the allowed claims to the client’s ID token or access token.

  4. All data sharing events are recorded in the Consent Ledger for future reference.

  5. For downstream microservices needing select user data, claims are securely synced using the MCP protocol — maintaining minimal data exposure.

  6. Admins or auditors can review decision rationales in a dedicated dashboard, ensuring accountability.


Unique Value Proposition

  • Privacy-first: AI-powered data minimization enforces the principle of least privilege

  • Scalable: Automatically adapts claim sharing for hundreds of clients across multiple business units

  • Compliant: Supports evolving regulatory mandates with granular consent and audit trails

  • Explainable: Builds stakeholder confidence with transparent claim decisioning

  • Reusable: Applicable across industries from BFSI to Healthcare and SaaS


Tech Stack Overview

Component Technology
Identity & Auth Keycloak (SPI Extensions)
AI Engine GPT-4o mini (OpenAI API)
Backend Service Spring Boot + WebClient
Database PostgreSQL (Consent Ledger)
Protocol MCP (Microservice Protocol)
Deployment Docker / Calibo
Admin UI (optional) React / Thymeleaf

Sample Code Snippet: AI-Driven Claim Mapper SPI

public class AiDrivenClaimMapper implements ProtocolMapper, OIDCAdvancedClaimToTokenMapper {
    @Override
    public void transformAccessToken(TokenMapperContext context) {
        AccessToken token = context.getAccessToken();
        UserModel user = context.getUserSession().getUser();
        ClientModel client = context.getClientSession().getClient();

        Map<String, Object> inputPayload = Map.of(
            "username", user.getUsername(),
            "email", user.getEmail(),
            "clientId", client.getClientId(),
            "loginIp", context.getSession().getContext().getConnection().getRemoteAddr()
        );

        List<String> claimsToRelease = AiService.getAllowedClaims(inputPayload);

        if (claimsToRelease.contains("email")) {
            token.getOtherClaims().put("email", user.getEmail());
        }
        if (claimsToRelease.contains("phone")) {
            token.getOtherClaims().put("phone", user.getFirstAttribute("phone"));
        }
    }
}

Conclusion

The Smart Federated Identity Hub is a game-changer for enterprises looking to reconcile seamless user experience with strict data privacy and security requirements. By combining the power of Keycloak’s extensibility with AI-driven contextual claim decisions, this solution not only improves security and compliance but also future-proofs identity management for the evolving digital landscape.

If you want to explore how AI can transform identity management in your organization or need help building a privacy-first identity architecture, reach out! The future of IAM is smart, context-aware, and explainable.


Would you like me to help prepare detailed implementation guides or demo videos next?

May 14, 2025

๐Ÿง‘‍๐Ÿ’ป Why Apple SSO Doesn't Return First and Last Name After First Login (and How to Handle It)

Single Sign-On (SSO) has become the gold standard for seamless user authentication. With providers like Google, Facebook, and Apple, integrating social login has never been easier. But when using Apple SSO, many developers face a confusing issue:

After the first login, Apple no longer returns the user's first and last name.

This behavior isn't a bug — it's by design. In this blog, we’ll dive into:

  • Why Apple behaves this way

  • How it's different from Google and Facebook

  • How to fix it in your app

  • Whether you can use Apple’s private relay email for OTP/communication


๐Ÿ Why Apple Doesn’t Return Name After First Login — By Design

Apple is known for putting user privacy first, and its SSO implementation reflects that.

When a user signs in using Apple for the first time, Apple returns the given_name, family_name, and optionally the email. However, subsequent logins will not return the name again, regardless of scopes.

๐Ÿ“œ Apple Developer Docs:
“Apple only shares user information such as name and email once, during the initial authorization.”

This is intentional to:

  • Minimize personal data shared with third-party apps

  • Give users complete control over their identity

  • Ensure developers store data responsibly


๐Ÿ” Why This Is Not an Issue with Google or Facebook

Both Google and Facebook take a more traditional OAuth 2.0 approach. When requested via appropriate scopes (profile, email), they consistently return:

  • First name

  • Last name

  • Profile picture

  • Email

Feature Apple Google / Facebook
Name returned always ❌ Only on first login ✅ On every login
Email always returned ✅ Yes (if allowed) ✅ Yes
Can hide real email ✅ Yes (private relay option) ❌ No
Privacy-first approach ✅ Very strict ❌ Less strict

๐Ÿ› ️ How to Fix the Missing Name Issue

To build a robust Apple SSO integration, here’s what you should do:

✅ 1. Store the Name at First Login

After the first login, extract and persist the name in your backend.

Map<String, Object> claims = decodeJwt(appleIdToken);
String firstName = (String) claims.get("given_name");
String lastName = (String) claims.get("family_name");

if (firstName != null && lastName != null) {
    userService.saveUserName(userId, firstName, lastName);
}

๐Ÿ” 2. Fetch Name From Your DB for Later Logins

Since Apple won’t send it again, use the stored name for future user sessions:

User user = userRepository.findByAppleSub(appleSub);
String name = user.getFirstName() + " " + user.getLastName();

✏️ 3. Prompt User If Name Was Never Captured

If the name wasn’t captured during the first login (e.g., due to a bug or user canceling), prompt the user to enter it manually.


๐Ÿ“ง Can You Use Apple’s Private Relay Email for OTP and Communication?

Yes! If a user chooses “Hide My Email” during Apple SSO, Apple generates a relay address like:

randomstring@privaterelay.appleid.com

✅ You Can Send OTPs and Emails to It

Apple forwards emails sent to this relay address to the user’s actual Apple ID inbox. You can use it for:

  • OTPs

  • Welcome emails

  • Password reset links

  • Transactional notifications

Apple guarantees delivery as long as your domain is registered and emails are compliant.

๐Ÿ”’ Key Considerations

Aspect Details
Relay Validity Relay remains active while the user uses your app
SPF/DKIM Required Set up email authentication to avoid spam filtering
No Marketing Emails Stick to transactional emails; avoid promotional content
Reply-to Address Set it up if you expect users to reply

๐Ÿ“ฅ Can Users Access It?

Absolutely. Users receive emails sent to @privaterelay.appleid.com in their actual inbox, just like any other email. They typically don’t see or interact with the relay address directly.


๐Ÿงฉ Bonus: How to Detect First-Time Apple Login

You can determine if it's a first-time login based on whether given_name and family_name are present in the ID token or the user JSON payload. If they're missing, it's a returning login.


๐Ÿงญ Final Thoughts

Apple's approach to SSO is driven by a strong privacy philosophy. While it may introduce some extra work for developers, it's a positive step for user data protection.

To ensure a smooth experience:

  • Store user name on first login

  • Use Apple’s private relay email confidently for OTPs and communication

  • Respect user privacy — and be ready to ask for missing info if needed


Need Help With Apple, Google, or Facebook SSO in Spring Boot or WebFlux?
I help teams build secure and privacy-conscious SSO integrations. Reach out if you’d like a tailored solution!


Would you like this in HTML format or exported as a file for publishing?

๐Ÿš€ Micronaut vs Spring Boot: The Ultimate Cloud-Native Java Showdown (AWS Lambda, EC2, Spot Instances)

  • In the age of microservices and serverless, Java still rules — but the framework you choose can dramatically impact cost, performance, and developer experience.

This blog breaks down a practical, head-to-head comparison between Micronaut and Spring Boot, with a special focus on AWS Lambda, EC2, and Spot Instances.


๐ŸŒŸ TL;DR Summary

Criteria Micronaut Spring Boot
๐Ÿš€ Startup Time Ultra-fast (20–100ms) Moderate to slow (500ms–3s)
๐Ÿ’พ Memory Usage Low (30–60MB typical) Higher (100–300MB typical)
๐Ÿง  Dependency Injection Compile-time (AOT) Runtime (reflection-heavy)
☁️ Serverless Fit ✅ Excellent for AWS Lambda ⚠️ Possible but slower cold starts
๐Ÿ’ธ Cost Efficiency ✅ Great for Spot/Lambda ⚠️ More costly in cold-start/serverless
๐Ÿ” Ecosystem Lightweight, focused Huge ecosystem, mature integrations
๐Ÿ“‰ Disadvantages Smaller community, limited plugins Slower boot, higher memory use

๐Ÿ” 1. Architecture Difference

Feature Micronaut Spring Boot
Dependency Injection AOT (compile-time) – no reflection Runtime reflection-based
Bean Instantiation Fast, direct bytecode-generated Slower due to dynamic proxies & reflection
Native Image Support First-class (GraalVM, small images) Supported but complex and large native images

Takeaway: Micronaut was built for cloud-native from the ground up, Spring Boot evolved into it.


⚡ 2. AWS Lambda: Cold Start Matters

Aspect Micronaut Spring Boot
Cold Start Time ~20–100ms (JVM), <10ms (native) ~1–3 seconds (JVM), ~700ms (native)
Memory Footprint ~30–60MB ~150–300MB
Cost Implication ✅ Lower Lambda invocation costs ⚠️ Higher cold start costs

๐Ÿ’ฐ AWS Lambda Cost Snapshot (Monthly Estimate):

Scenario: 1 million monthly invocations, 512MB memory, 1s avg runtime

Framework Monthly Cost (USD)
Micronaut ~$4.00
Spring Boot ~$10.00

๐Ÿ‘‰ Micronaut can save 2–3x costs in cold-start-heavy use cases.


๐Ÿ’ก 3. EC2 / Spot Instances: Boot Fast, Scale Faster

Area Micronaut Spring Boot
Boot Time (EC2 restart) ~300ms ~2–5 seconds
Ideal for Spot Scaling ✅ Yes ⚠️ Less ideal due to slow start
Memory Footprint (512MB RAM) ✅ Fits easily ⚠️ May require memory tuning

EC2 Cost Snapshot (t4g.small - ₹500/month baseline):

  • Micronaut allows you to pack more services per instance (lower infra cost).

  • Spring Boot might require more EC2 nodes or larger instances = higher cost.


⚖️ 4. Disadvantages: Honest Look

❌ Micronaut Disadvantages:

  • Smaller ecosystem (e.g., fewer libraries and integrations)

  • Less community support compared to Spring

  • Learning curve due to compile-time DI model

  • GraalVM native images require careful tuning (startup vs throughput)

❌ Spring Boot Disadvantages:

  • Slower startup (problematic for Lambda/serverless)

  • Higher memory use → increased cloud cost

  • Reflection-heavy = poor native image performance

  • Runtime dependency scanning slows boot


๐Ÿงช 5. Performance Benchmark (JVM)

Metric Micronaut (JVM) Spring Boot (JVM)
Startup Time ~200–400ms ~1.5–3s
Memory Usage ~50MB ~150–300MB
Throughput (req/s) High High (with warm JVM)
Native Image Time <30ms (Micronaut native) ~500–800ms (Spring Native)

๐Ÿ“Œ Micronaut shines in startup + Lambda; Spring Boot wins for always-on services with rich dependencies.


๐Ÿงฐ 6. Ecosystem & Tooling

Category Micronaut Spring Boot
CLI / Scaffolding Yes (mn CLI) Yes (spring init)
Dev Tools Hot reload (limited), Gradle/Maven DevTools, Spring Dev Launcher
Libraries REST, gRPC, Kafka, AWS SDK Huge ecosystem, legacy & modern support
IDE Support IntelliJ, VSCode IntelliJ, Eclipse, STS, VSCode

๐Ÿ“Œ 7. Ideal Use Cases

Use Case Recommended Framework
AWS Lambda ✅ Micronaut
Short-lived background jobs ✅ Micronaut
Resource-constrained environments ✅ Micronaut
Legacy migration ✅ Spring Boot
Complex integrations (JMS, JPA) ✅ Spring Boot
Large teams with Spring skills ✅ Spring Boot

๐Ÿ”ฎ 8. What's Next: Micronaut + Galvium

Micronaut’s partnership with Galvium (an upcoming JVM runtime) aims to cut JVM cold starts down to ~10mswithout native compilation.

Galvium + Micronaut could redefine how Java works in:

  • Instant cold starts

  • Serverless

  • Autoscaling pods

It’s early, but Micronaut is future-proofing Java cloud apps.


✅ Conclusion

Summary Verdict
Cloud-native design ✅ Micronaut
Mature enterprise ecosystem ✅ Spring Boot
Fast cold start and low memory ✅ Micronaut
Best for long-running heavy apps ✅ Spring Boot
Cost-efficient for AWS Lambda/EC2 ✅ Micronaut
Easier onboarding & hiring ✅ Spring Boot

๐Ÿ“ Want More?

Would you like this blog exported as:

  • ✅ Markdown (.md)

  • ✅ HTML

  • ✅ Publish-ready Medium/Dev.to format

  • ✅ With diagrams comparing startup/memory graphs

Just say the word and I’ll generate it for you!

May 10, 2025

๐Ÿ›ก️ Understanding the Proxy Design Pattern in Java — Real-World Usage and Examples

When it comes to structural design patterns, the Proxy Pattern stands out as one of the most powerful tools for controlling access to an object, managing performance, and adding extra functionality transparently. From security to lazy loading, the proxy pattern has wide-reaching applications in modern Java development — especially in frameworks like Spring and Hibernate.

In this article, we’ll explore:

  • ✅ What is the Proxy Design Pattern?

  • ๐Ÿ” Real-world analogies

  • ๐Ÿ› ️ Types of Proxies (Virtual, Protection, Remote, etc.)

  • ☕ Java implementation

  • ๐ŸŒฑ How Spring uses proxies

  • ๐Ÿ“Š Advantages and trade-offs


๐Ÿง  What is the Proxy Pattern?

Proxy Pattern provides a surrogate or placeholder for another object to control access to it.

Think of it as a gatekeeper or middleman that decides whether or how to pass a request to the real object.

It belongs to the structural family of design patterns and is especially useful when:

  • Creating the actual object is expensive.

  • You want to control access to the real object.

  • You need to add extra behavior (e.g., logging, security) without modifying the real object.


๐ŸŽฏ Real-world Analogy

Imagine you're trying to meet a high-profile CEO. You can't just walk into their office — you go through their secretary (proxy) first, who checks your purpose, filters calls, and decides whether to forward your request.


๐Ÿงฑ Types of Proxies in Java

Type Purpose
๐Ÿ”„ Virtual Proxy Defers creation of resource-heavy objects until needed
๐Ÿ” Protection Proxy Controls access based on permissions or user roles
๐ŸŒ Remote Proxy Represents objects in a different address space (e.g., RMI)
๐Ÿ“ Logging Proxy Adds behavior like logging, caching, or performance tracking
๐Ÿงช Smart Proxy Adds extra actions (e.g., ref counting, access tracking)

๐Ÿ’ป Java Implementation — Virtual Proxy

Let's build a virtual proxy that delays the creation of a large image until it's needed.

Step 1: Create a Common Interface

public interface Image {
    void display();
}

Step 2: The Real Object

public class RealImage implements Image {
    private String fileName;

    public RealImage(String fileName) {
        this.fileName = fileName;
        loadFromDisk();
    }

    private void loadFromDisk() {
        System.out.println("Loading " + fileName);
    }

    public void display() {
        System.out.println("Displaying " + fileName);
    }
}

Step 3: The Proxy Class

public class ProxyImage implements Image {
    private RealImage realImage;
    private String fileName;

    public ProxyImage(String fileName) {
        this.fileName = fileName;
    }

    public void display() {
        if (realImage == null) {
            realImage = new RealImage(fileName); // expensive
        }
        realImage.display();
    }
}

Step 4: Client Code

public class Main {
    public static void main(String[] args) {
        Image image = new ProxyImage("test.jpg");

        System.out.println("Image created");

        image.display(); // loads and displays
        image.display(); // only displays
    }
}

Output:

Image created
Loading test.jpg
Displaying test.jpg
Displaying test.jpg

๐Ÿงฐ Spring Framework and Proxy Pattern

Spring relies heavily on proxies, especially for:

✅ AOP (Aspect-Oriented Programming)

  • Cross-cutting concerns like logging, transactions, and security are implemented using dynamic proxies (JDK or CGLIB).

✅ @Transactional

  • When you use @Transactional, Spring creates a proxy around the bean and applies transaction boundaries before and after the method call.

Example:

@Transactional
public void transferMoney(Account from, Account to, BigDecimal amount) {
    // Transactional logic
}

Here, Spring uses a proxy to manage the transaction behind the scenes.


๐Ÿ“Š Advantages of the Proxy Pattern

  • ✔️ Controls access to the real object

  • ✔️ Adds functionality without changing original code

  • ✔️ Supports lazy initialization

  • ✔️ Can improve performance and security


⚠️ Drawbacks

  • ❌ Adds extra complexity

  • ❌ Overhead if too many proxies are layered

  • ❌ Harder debugging in heavily proxied environments (especially dynamic proxies)


๐Ÿ“ฆ When to Use the Proxy Pattern

Use Case Recommended?
Lazy-loading large resources ✅ Yes (Virtual Proxy)
Security enforcement ✅ Yes (Protection Proxy)
Access to remote resources ✅ Yes (Remote Proxy)
Adding cross-cutting concerns ✅ Yes (Smart/Logging Proxy, AOP)
Overusing proxies in simple apps ❌ Avoid

๐Ÿงพ Final Thoughts

The Proxy Pattern is a powerful tool in your Java toolbox. Whether you're optimizing performance, enforcing security, or adding dynamic behavior, the proxy allows you to extend behavior transparently without touching the real business logic.

Frameworks like Spring and Hibernate make heavy use of this pattern under the hood — so understanding it is key to writing better, cleaner, and more efficient Java applications.


✨ TL;DR

  • Proxy Pattern = Surrogate for real object

  • Types: Virtual, Protection, Remote, Logging

  • Java and Spring use proxies for lazy loading, AOP, and security

  • Recommended for clean separation and controlled object access


Would you like this blog converted to Markdown, PDF, or a LinkedIn/Medium-optimized format?