JWT Authorization Grant in Keycloak with Node.js

George Thomas George Thomas 3 min read

Introduction

This article builds on an earlier post about JWT Authorization Grant using an external Identity Provider.

Previously, we used Auth0 to issue the JWT assertion required for the JWT Bearer Grant flow. In this article, we replace Auth0 with a custom Node.js application that issues a signed JWT. This JWT is then used as an assertion to request an access token from Keycloak.

This flow requires configuring a JWT-based Identity Provider, in Keycloak 26.6+

Architecture

Custom Node.js application (JWT Issuer)
        ↓
JWT (Assertion)
        ↓
Keycloak (JWT Identity Provider Validation)
        ↓
Keycloak Access Token

💡 In this setup, the Node.js application acts as an external Identity Provider, and Keycloak acts as a broker that validates and trusts the JWT.

For more details on JWT Authorization Grant, please visit this link.


Implementation Steps


Step 1: Create a Node.js Application to Generate JWT

Install Dependencies

npm install jsonwebtoken uuid

Generate Asymmetric Keys

JWT Bearer flow uses RS256 (asymmetric encryption).

KeyPurpose
🔐 Private KeyUsed by Node.js to sign JWT
🔓 Public KeyShared with Keycloak for verification
# Generate private key
openssl genpkey -algorithm RSA -out private.pem -pkeyopt rsa_keygen_bits:2048

# Extract public key
openssl rsa -pubout -in private.pem -out public.pem

Generate JWT (Node.js)

const jwt = require('jsonwebtoken');
const { v4: uuidv4 } = require('uuid');
const fs = require('fs');

// Load PRIVATE KEY (used for signing)
const privateKey = fs.readFileSync('./private.pem', 'utf8');

const now = Math.floor(Date.now() / 1000);


// JWT payload
const payload = {
  iss: 'http://localhost:3000',   // Node.js application
  sub: 'nodejsuser-1234',  //unique user at Node.js
  aud: 'http://localhost:8080/realms/acme', //Keycloak URL for realm acme
  jti: uuidv4(),
  iat: now
};

// Sign JWT
const token = jwt.sign(payload, privateKey, {
  algorithm: 'RS256',
  expiresIn: '5m',   // automatically adds exp claim
});

console.log('Generated JWT:\n', token);

Project Structure


project/
 ├── private.pem   ❗ KEEP SECRET
 ├── public.pem    ✅ SHARE WITH KEYCLOAK
 └── app.js

Step 2: Configure JWT Identity Provider in Keycloak

Navigate to:

Identity Providers → Add Provider → JWT Authorization Grant

Configure:

  • Alias: jwt-authorization-grant
  • Issuer:http://localhost:3000(Must exactly match iss in JWT)
  • Validating Public Key:
    • Paste contents of public.pem
    • Disable JWKS URL (since we are uploading manually)
Keycloak-like admin console showing Jwt-authz-grant provider settings with fields for alias, issuer, keys, and Save button on the right panel.
Identity Provider

Step 3: Configure Keycloak Client

Create a client:

  • Client Type: Confidential
  • Enable:
    • ✅ JWT Authorization Grant

Important Configuration:

Set:

Allowed Identity Providers = jwt-authorization-grant

⚠️ This must match the alias of the Identity Provider created earlier.

Capability config panel with switches for Client authentication (On) and Standard flow enabled; JWT Authorization Grant checked and highlighted with a purple underline; other options like Direct access grants and OAuth2 device grant are Off/Unchecked.
Keycloak Client

Step 4: Map External User to Keycloak User

In JWT Authorization Grant (via IDP), Keycloak does not automatically map users, and mappers are not available for this provider type.

So we must manually link users.


Create a User

Example:

Username: [email protected] 

Link Identity Provider

  1. Open the user in Keycloak
  2. Go to Identity Provider Links
  3. Under Available Identity Providers, find:jwt-authorization-grant
  4. Click Link Account
    • Specify userid and username – in our case nodejsuser-1234 (it should match sub claim in JWT)

Now the external user (sub) is linked to the specified Keycloak user.


Step 5: Test the Flow

Run Node.js App

Generate JWT.

Call Token Endpoint (append curl -X to below)

POST "http://keylcoak-hostname/realms/your-realm/protocol/openid-connect/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer" \
  -d "client_id=custom-client" \
  -d "client_secret=the-client-secret" \
  -d "assertion=<JWT_ASSERTiON>" 

Common Errors and Fixes

❌ No Identity Provider for provided issuer

  • Ensure iss matches IDP issuer exactly

❌ User not found

  • Ensure:
    • User exists
    • Identity Provider is linked and provide values matching sub of JWT issued by Node,js

❌ Signature validation failed

  • Verify:
    • Correct public key in Keycloak
    • Matching private key in Node.js

Key Takeaways

  • In Keycloak 26.6+, JWT Authorization Grant requires an Identity Provider configuration
  • iss must be a valid URL and match the IDP
  • Node.js acts as a trusted external token issuer
  • User mapping must be handled manually using Link Account

Summary

In this article, we explored how to implement JWT Authorization Grant in Keycloak using a custom Node.js application as the token issuer.

This approach is useful when integrating with:

  • Federated IAM architectures.
  • Custom identity systems
  • External authentication providers

About Skycloak

Skycloak is a fully managed Keycloak platform hosted in the cloud. It enables organizations to leverage the power of open-source Keycloak IAM without the operational overhead of installing, maintaining, and scaling production-grade Keycloak environments — delivered securely and cost-effectively.

If you’re new to Skycloak, visit the Skycloak Getting Started Guide to learn more

George Thomas
Written by George Thomas IAM Engineer

George is an IAM engineer with 23+ years in software engineering, including 14+ years specializing in identity and access management. He designs and modernizes enterprise IAM platforms with deep expertise in Keycloak, OAuth 2.0, OpenID Connect, SAML, and identity federation across cloud and hybrid environments. Previously at Trianz and a long-term contributor to Entrust IAM product engineering, George authors Skycloak's technical Keycloak tutorials.

Ready to simplify your authentication?

Deploy production-ready Keycloak in minutes. Unlimited users, flat pricing, no SSO tax.

© 2026 Skycloak. All Rights Reserved. Design by Yasser Soliman