Getting Started with Keycloak (Or Why You Shouldn't)

    Most Keycloak tutorials assume you need it. You probably don't. You need authentication, sure. But for most projects, implementing Keycloak is like drinking from a firehose when all you need is a glass of water.

    Already decided you need Keycloak? Here's how to set up Keycloak SSO in 30 minutes. Fair warning: you'll get a dev environment running quickly, but it'll take 12 weeks until it actually works properly in production. That's not a Keycloak problem, that's an IAM reality.

    Here's the thing about Keycloak - it's not really about authentication. It's about Single Sign-On (SSO) and complete user lifecycle management. When someone joins your company, moves departments, or leaves. When BigCorp acquires you and suddenly 5,000 employees need access. When the auditor asks "who had access to what, when, and why?"

    With simpler frameworks like Passport.js, NextAuth, or Devise, you're answering the question: "How do users log in?"

    With Keycloak, you're dealing with something bigger: "How do we manage identity across our entire organization?"

    That's a fundamentally different challenge. Most developers learn this the hard way - implementing Keycloak's technical features without understanding the business problems they solve.

    Stage 1: You Have 50 Users (You Don't Need Keycloak)

    Your requirements:

    • Users can log in with email/password
    • Basic session management
    • Password reset via email

    Time to implement with Passport.js: 2 hours
    Time to implement with Keycloak: 2 weeks

    Here's your entire authentication system:

    javascript
    // Complete authentication in 47 lines const passport = require('passport'); const LocalStrategy = require('passport-local').Strategy; const bcrypt = require('bcrypt'); // This is all you need for basic auth passport.use(new LocalStrategy({ usernameField: 'email' }, async (email, password, done) => { const user = await User.findOne({ email }); if (!user) return done(null, false); const valid = await bcrypt.compare(password, user.password); if (!valid) return done(null, false); return done(null, user); } )); // Login endpoint app.post('/login', passport.authenticate('local'), (req, res) => { res.json({ user: req.user }); }); // Logout app.post('/logout', (req, res) => { req.logout(); res.json({ message: 'Logged out' }); }); // Password reset app.post('/reset-password', async (req, res) => { const token = crypto.randomBytes(20).toString('hex'); await User.updateOne( { email: req.body.email }, { resetToken: token, resetExpires: Date.now() + 3600000 } ); await sendEmail(req.body.email, `Reset link: ${process.env.URL}/reset/${token}`); res.json({ message: 'Email sent' }); }); // Protected route app.get('/dashboard', ensureAuthenticated, (req, res) => { res.json({ data: 'Secret data', user: req.user }); }); function ensureAuthenticated(req, res, next) { if (req.isAuthenticated()) return next(); res.status(401).json({ error: 'Not authenticated' }); }

    That's it. You're done. Your CEO is happy. Your users can log in. Don't install Keycloak.

    But what about JWT tokens?

    You don't need them yet. Sessions work fine for a single application. JWTs become necessary when you have multiple services:

    javascript
    // You need JWTs when you have multiple services // Service A (your main app) - issues tokens app.post('/login', async (req, res) => { const user = await authenticateUser(req.body); const token = jwt.sign( { id: user.id, email: user.email }, process.env.JWT_SECRET, { expiresIn: '1h' } ); res.json({ token }); }); // Service B (your API) - validates tokens app.get('/api/data', (req, res) => { const token = req.headers.authorization?.split(' ')[1]; try { const user = jwt.verify(token, process.env.JWT_SECRET); res.json({ data: 'Secret data for ' + user.email }); } catch (err) { res.status(401).json({ error: 'Invalid token' }); } });

    Still just 20 lines. Still don't need Keycloak.

    Stage 2: You Add Google Login (Still Don't Need Keycloak)

    New requirement: "Our users want to login with Google"

    Time to add with Passport.js: 1 hour Time to add with Keycloak: 1 day (after you understand realm configuration)

    javascript
    // Add Google login in 15 lines const GoogleStrategy = require('passport-google-oauth20').Strategy; passport.use(new GoogleStrategy({ clientID: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, callbackURL: "/auth/google/callback" }, async (accessToken, refreshToken, profile, done) => { let user = await User.findOne({ googleId: profile.id }); if (!user) { user = await User.create({ googleId: profile.id, email: profile.emails[0].value, name: profile.displayName }); } return done(null, user); } )); app.get('/auth/google', passport.authenticate('google', { scope: ['profile', 'email'] }) ); app.get('/auth/google/callback', passport.authenticate('google'), (req, res) => res.redirect('/dashboard') );

    You now support both email/password and Google login. Total code: ~70 lines. Keycloak would require Docker, realm setup, client configuration, and understanding OAuth2 flows you don't need to understand yet.

    Stage 3: Partner API Access - The Hidden Complexity

    New requirement: "We need to give our partners API access with their own keys"

    This is where things get interesting. You're not just authenticating users anymore - you're managing service accounts, API keys, rate limiting, and audit trails.

    javascript
    // What starts simple... app.post('/api/authenticate', (req, res) => { const apiKey = req.headers['x-api-key']; const client = await Client.findOne({ apiKey }); if (!client) return res.status(401).json({ error: 'Invalid API key' }); res.json({ token: generateToken(client) }); }); // ...quickly becomes a nightmare // - How do you rotate API keys? // - How do you rate limit per client? // - How do you audit which client accessed what? // - How do you revoke access immediately? // - How do you implement OAuth2 client credentials flow? // - How do you manage scopes per client?

    With simpler tools, you're building your own OAuth2 server. With Keycloak, service accounts are first-class citizens:

    bash
    # Create a service account client in Keycloak docker exec keycloak /opt/keycloak/bin/kcadm.sh create clients -r myrealm \ -s clientId=partner-api \ -s enabled=true \ -s serviceAccountsEnabled=true \ -s publicClient=false \ -s secret=partner-secret \ -s 'defaultClientScopes=["api-read", "api-write"]' # Partner gets token using client credentials curl -X POST http://localhost:8080/realms/myrealm/protocol/openid-connect/token \ -d "grant_type=client_credentials" \ -d "client_id=partner-api" \ -d "client_secret=partner-secret"

    Now you have proper client credentials flow, automatic rate limiting, complete audit trails, immediate revocation, and scope management. Building this yourself is months of work and security vulnerabilities.

    Stage 4: Multiple Applications - The SSO Tipping Point

    New requirement: "We're building a mobile app and an admin panel. Users should login once and access everything."

    Now we're entering Single Sign-On territory. With Passport.js, things get messy:

    javascript
    // Option 1: Shared session store (not true SSO) const RedisStore = require('connect-redis')(session); const redis = require('redis'); const redisClient = redis.createClient(); // App 1, App 2, App 3 all use same session store app.use(session({ store: new RedisStore({ client: redisClient }), secret: 'shared-secret', cookie: { domain: '.yourcompany.com' } // Critical for sharing })); // Problem: Doesn't work for mobile apps // Problem: Doesn't work across different domains // Problem: Not really SSO, just shared sessions

    or

    javascript
    // Option 2: Build your own OAuth2 server (don't) const oauth2orize = require('oauth2orize'); const server = oauth2orize.createServer(); // 200+ lines of code to implement OAuth2 properly // Tokens, refresh tokens, authorization codes, PKCE... // Security vulnerabilities waiting to happen

    This is where things shift. When you need real SSO across multiple applications, especially with mobile apps, Keycloak starts making sense. Even here though, you're looking at weeks to get production-ready. If you're at this stage, play with Keycloak SSO to understand the complexity you're signing up for. It's eye-opening.

    Stage 5: Enterprise Integration - Welcome to the Big Leagues

    New requirement: "BigCorp wants their 5,000 employees to login with their Windows credentials"

    With simpler frameworks like Passport.js, you're looking at weeks of custom LDAP code. With Keycloak, it's configuration - but here's what's interesting: it's not just technical configuration anymore. You're managing identity lifecycle.

    When Sarah from BigCorp moves from Sales to Engineering:

    • Her Active Directory groups change
    • Her application permissions need updating
    • Her access to customer data should be revoked
    • Her access to GitHub should be granted
    • Audit trail must show the change

    This is the "mover" in joiner/mover/leaver. Passport.js doesn't even have concepts for this. Keycloak does, because it's not an authentication library - it's an IAM platform.

    But wait, there's more: BigCorp will also ask "Is your system GDPR compliant?"

    Here's something nobody mentions: Keycloak out of the box is NOT GDPR compliant. But it CAN be made compliant - Keycloak provides all the building blocks, you just need to assemble them correctly.

    The most obvious requirements that need configuration:

    Information Duty (GDPR Art. 13): Before collecting any data, you must inform users about data processing. Keycloak's default registration flow collects first, informs never. Users enter their email, username, personal data - all stored immediately without any privacy notice.

    Explicit Consent (GDPR Art. 6(1)(a)): Users must explicitly consent to data processing before you activate their account. Keycloak's default activates accounts immediately upon registration. No consent checkbox. No "I agree to terms." The data is already stored.

    And that's just the beginning. Password reset emails contain PII with no retention controls. Audit logs might violate data retention policies. No built-in right to be forgotten workflows. No data portability exports. Each requires custom configuration.

    Why isn't this pre-configured? The reasonable answer: every company's GDPR implementation is different - what works for a German B2B SaaS won't work for a French consumer app. Keycloak gives you the flexibility to implement your specific requirements rather than forcing one interpretation of GDPR.

    If you're targeting enterprise customers in Europe, this isn't optional - it's table stakes.

    Stage 6: When Compliance Becomes Life or Death

    New requirement: "We need to know who accessed what, when, implement MFA for admins, auto-disable accounts after 90 days of inactivity, and prove to auditors that terminated employees can't access anything."

    You're not solving technical problems anymore. You're solving business and compliance problems:

    • Joiner: New employee starts Monday. They need exactly the right access on day one.
    • Mover: Employee changes role. Old access revoked, new access granted, audit trail created.
    • Leaver: Employee terminated. Access removed everywhere within 1 hour. Proof for auditors.

    Try implementing this with Passport.js and you'll build your own IAM system. Poorly.

    But here's the extreme case that shows why mature IAM matters:

    During a cardiac emergency, an Emergency Room doctor needs immediate access to any patient record. Normal HIPAA controls could cost lives. But every emergency access must create an audit trail, trigger review workflows, and generate compliance reports within 24 hours.

    This is called "break-glass access" - the ability to override normal permissions in emergencies while maintaining complete accountability. With Keycloak, you can implement this. With simpler tools, you're gambling with lives and lawsuits. The complexity isn't bureaucracy - it's necessary.

    Building this yourself isn't just technically challenging - it's ethically questionable. When IAM failures can cost lives or millions in compliance fines, you need a battle-tested system.

    The Reality of Learning Keycloak

    Here's what nobody tells you: Keycloak has one of the steepest learning curves in modern tech. Not because it's poorly designed, but because you're not just learning a tool - you're learning an entire domain (IAM) that most developers never properly study.

    The typical journey: Week 1 feels easy (Docker running, users logging in). Week 3 is pure confusion (redirect_uri errors, CORS failures, tokens expiring randomly). By month 3, you might understand the basics. After 6 months, you're comfortable. True expertise? That takes years, and involves understanding business requirements as much as technical configuration.

    The hard truth: if you're just looking for authentication, this learning curve isn't worth it. If you're building proper identity management, it's unavoidable.

    Three Ways Companies Learn This Lesson the Hard Way

    If any of these scenarios sound familiar, you're not alone:

    "We'll add SSO later" - Built with Passport.js because it was quick. Two years later, enterprise client needs SAML. Team estimates 4 weeks (with buffer). Six months later, still rebuilding auth layer, haven't touched SAML. Client signed with competitor. $2M expansion gone.

    "Let's do it right from day one" - 50 users but CTO insists on "enterprise-ready" and "building for scale." Three months debugging SAML configurations while competitor ships features weekly. They get to market first. You never catch up.

    "Basic auth is fine for now" - No MFA, no audit logs, sessions never expire. Data breach from password reuse. Fines, customer exodus, fire sale acquisition. All preventable.

    The pattern is clear: using Keycloak too early wastes months. Using it too late costs millions. The sweet spot? Usually somewhere between Stage 3 and 4 above - when you start managing service accounts or need real SSO.

    The Decision Framework

    After implementing auth for 50+ projects, here's what we've learned:

    Use Simpler Frameworks (Passport/NextAuth/Devise) When:

    • Single application
    • < 100 users
    • Basic login (email/password + maybe Google)
    • No enterprise integration
    • No compliance requirements
    • Technical team handles auth
    • You're solving: "How do users log in?"

    Consider Keycloak When:

    • Multiple applications (real SSO needed)
    • Enterprise integration (LDAP/AD)
    • Compliance requirements
    • 1000+ users
    • HR needs to manage access
    • You're solving: "How do we manage identity lifecycle?"

    Definitely Use Keycloak When:

    • M&A activity (integrating multiple companies)
    • Multiple protocols (OIDC + SAML)
    • Regulated industry (finance, healthcare)
    • B2B SaaS with enterprise clients
    • You're solving: "How do we prove compliance?"

    Consider Auth0/Okta When:

    • Need it working TODAY
    • No DevOps team
    • OK with $1000+/month
    • US data residency acceptable
    • Standard flows cover your needs
    • You're solving: "We don't want to solve this"

    When you have complex custom requirements (like that Emergency Room break-glass scenario), Keycloak's open source nature becomes crucial. You can write custom authenticators, modify flows, add specific audit requirements. With commercial solutions, custom requirements mean $50K-$250K just to build it, plus $30K-$80K/year ongoing (yes, really) or "sorry, we don't support that."

    Red Flags You're Outgrowing Simple Auth

    Watch for these warning signs that you need to level up from simple auth to Keycloak:

    • Your API partners are asking about OAuth2 client credentials flow
    • You're building a second application and thinking "users shouldn't need to login twice"
    • Sales keeps losing deals because "we need SAML"
    • You're storing API keys in a database column called "api_key"
    • The auditor asked for an access report and you ran a SQL query
    • You built your own "admin panel" for user management
    • Your session management code is becoming a complex state machine
    • Someone asked about "service accounts" and you weren't sure what they meant

    If you're seeing 2-3 of these signs, start planning your migration. If you're seeing 4+, you're already behind.

    The Knowledge Gap Nobody Talks About

    Here's what's fascinating: you can master every Keycloak feature - realms, clients, flows, mappers, federations - and still fail spectacularly at implementing IAM. Why? Because Keycloak documentation teaches you WHAT buttons to click, not WHEN or WHY to click them.

    The real expertise isn't knowing that Keycloak has "Authentication Flows" - it's knowing that your break-glass emergency access needs a custom authentication flow with step-up authentication, time-boxed elevation, and automated audit triggers. The documentation won't teach you that. Stack Overflow won't either.

    This gap between technical features and business requirements is where most IAM projects fail. You implement user federation perfectly, but didn't realize you needed to handle the joiner/mover/leaver lifecycle. You configure SAML beautifully, but didn't know enterprise customers expect session timeout after 15 minutes of inactivity, not 15 minutes total. You set up audit events, but the format doesn't match what compliance auditors actually need.

    We built AuthPractice as an IAM Simulator specifically to bridge this gap. Not another "click here to configure realm" tutorial, but scenarios where you experience why each feature exists. The panicked Friday when a terminated employee's access must be revoked everywhere. The audit request that needs proof of access controls. The acquisition where 2,000 new users need precisely scoped access by Monday morning.

    Because in the end, IAM expertise isn't about knowing Keycloak, Auth0, or Okta. It's about understanding identity patterns that transcend any specific tool. Once you understand why break-glass access exists and what we need to support it properly, implementing it in any system becomes straightforward. Once you've lived through discovering a terminated employee still accessing customer data months later, you'll never design identity systems the same way again.


    Quick test if you're unsure: If you understood the Passport.js examples but glazed over at 'break-glass access,' stick with Passport. You'll know it's time for Keycloak when compliance requirements keep you up at night, not technical challenges.