logo

Keycloak Token Validation for APIs

Securing APIs with Keycloak Tokens

Keycloak simplifies API security by validating tokens that confirm user identity and permissions. It ensures only authorized users access protected resources. Here’s what you need to know:

  • Token Structure: Tokens consist of a header, payload (user claims like roles, issuer, expiration), and signature for tamper detection.
  • Validation Methods:
    • Local Validation: Offline, fast, and avoids network calls.
    • Token Introspection: Real-time checks for revoked or expired tokens.
  • Implementation: Use Keycloak’s public key to verify tokens and validate claims like issuer (iss), expiration (exp), and audience (aud).
  • Framework Support: Keycloak integrates seamlessly with frameworks like Spring Boot and Express.js.

Quick Comparison:

Feature Local Validation Token Introspection
Performance High Moderate (network calls)
Real-time Revocation No Yes
Offline Capability Yes No
Security Moderate High

Keycloak also supports token lifecycle management, including expiration, revocation, and usage tracking. Short-lived tokens (e.g., 5-15 minutes for access tokens) and refresh tokens enhance security. For distributed systems, caching and monitoring tools like Redis or Skycloak can improve performance and detect suspicious activity.

Keycloak Access Token Validation | Backend JWT Verification

Keycloak Token Basics

Keycloak tokens act as digital credentials, confirming user identity and permissions. Let’s break down their structure and explore how to validate them effectively.

Token Structure and Components

A Keycloak token consists of three main parts:

  • Header: Contains metadata about the token, like its type and the signing algorithm used.
  • Payload: Holds claims about the user and their permissions.
  • Signature: Verifies the token’s integrity and helps detect tampering.

The payload includes critical claims necessary for API validation. Here’s a quick overview:

Claim Purpose Example Value
iss Token issuer URL https://auth.example.com/realms/master
sub Unique user identifier f81d4fae-7dec-11d0-a765-00a0c91e6bf6
exp Token expiration timestamp 1745841600 (April 28, 2025, 12:00:00 PM UTC)
aud Intended audience my-api-service
roles User’s assigned roles ["admin", "user"]

Token Validation Methods

There are two primary ways to validate Keycloak tokens: local validation and token introspection. Here’s what you need to know about each approach:

  • Local Validation: This method works offline, avoids network calls, and reduces server load. It’s efficient for most use cases where tokens don’t need real-time validation.
  • Token Introspection: This approach requires a network call to Keycloak’s introspection endpoint. It allows real-time checks for token validity, including immediate detection of revoked tokens. While more secure, it adds network overhead.

Here’s a comparison to help you decide which method suits your needs:

Requirement Recommended Method Reason
High Performance Local Validation No network calls, reducing latency
Real-time Revocation Token Introspection Ensures immediate status updates
Offline Capability Local Validation Works without relying on Keycloak’s availability
Maximum Security Token Introspection Provides up-to-date validation checks

For most APIs, local validation strikes a balance between performance and security. However, if your application handles sensitive information or requires immediate token revocation, token introspection might be worth the trade-off in performance.

Setting Up Token Validation

Once you’re familiar with token structure and validation methods, the next step is implementing token validation. This involves obtaining the public key and verifying tokens.

Getting the Public Key

To validate tokens locally, you need Keycloak’s public key. Retrieve it from your realm’s certificate endpoint:

https://{keycloak-domain}/realms/{realm-name}/protocol/openid-connect/certs

The endpoint returns a JSON Web Key Set (JWKS) containing the public key:

{
  "keys": [{
    "kid": "your-key-id",
    "kty": "RSA",
    "alg": "RS256",
    "n": "public-key-modulus",
    "e": "AQAB"
  }]
}

Once you have the public key, you can move on to verifying the token’s signature and claims.

Token Verification Steps

When verifying tokens, focus on these two key areas:

1. Signature Verification

A typical Java implementation for verifying the token’s signature looks like this:

Algorithm algorithm = Algorithm.RSA256(publicKey, null);
JWTVerifier verifier = JWT.require(algorithm)
    .withIssuer("https://your-keycloak-domain/realms/your-realm")
    .build();
DecodedJWT jwt = verifier.verify(token);

2. Claims Validation

Check the following claims to ensure the token is valid:

Claim What to Check Error Response
exp Current time must be less than the expiration time 401 – Token expired
iss Must match your Keycloak realm URL 401 – Invalid issuer
aud Must match your service ID 401 – Invalid audience
nbf Current time must be greater than the “not before” time 401 – Token not yet valid

For dynamic, real-time validation, token introspection is another option.

Using Token Introspection

Token introspection is a real-time validation method that uses Keycloak’s introspection endpoint:

POST /realms/{realm-name}/protocol/openid-connect/token/introspect

Include these headers in your request:

Content-Type: application/x-www-form-urlencoded
Authorization: Basic {client-credentials}

The server’s response will indicate whether the token is active and provide additional details:

{
  "active": true,
  "sub": "user-id",
  "client_id": "your-client",
  "username": "[email protected]",
  "exp": 1714492800
}

Handling Invalid Tokens

When token validation fails, respond with appropriate HTTP status codes and error messages:

Error Condition HTTP Status Response Example
Missing Token 401 {"error": "missing_token"}
Invalid Signature 401 {"error": "invalid_token"}
Expired Token 401 {"error": "token_expired"}
Invalid Claims 401 {"error": "invalid_claims"}
Revoked Token 401 {"error": "token_revoked"}

To enhance security, log validation failures:

logger.warn("Token validation failed: {} for IP: {}", 
    error.getMessage(), 
    request.getRemoteAddr()
);

For browser-based API calls, set appropriate CORS headers:

response.setHeader("WWW-Authenticate", 
    "Bearer realm=\"your-realm\", error=\"invalid_token\""
);
sbb-itb-9d854a3

API Implementation Guide

Learn how to integrate Keycloak token validation into your API with these framework-specific examples.

Implementation Examples

For Spring Boot, use built-in security filters to handle token validation:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.oauth2ResourceServer()
            .jwt()
            .jwtAuthenticationConverter(jwtAuthenticationConverter());

        http.authorizeRequests()
            .antMatchers("/api/public/**").permitAll()
            .antMatchers("/api/private/**").authenticated();
    }

    private JwtAuthenticationConverter jwtAuthenticationConverter() {
        JwtGrantedAuthoritiesConverter converter = new JwtGrantedAuthoritiesConverter();
        converter.setAuthoritiesClaimName("roles");
        converter.setAuthorityPrefix("ROLE_");

        JwtAuthenticationConverter jwtConverter = new JwtAuthenticationConverter();
        jwtConverter.setJwtGrantedAuthoritiesConverter(converter);
        return jwtConverter;
    }
}

For Express.js, use middleware to validate tokens by fetching the signing key from Keycloak’s JWKS endpoint:

const express = require('express');
const jwt = require('jsonwebtoken');
const jwksClient = require('jwks-rsa');

const client = jwksClient({
    jwksUri: 'https://{keycloak-domain}/realms/{realm-name}/protocol/openid-connect/certs'
});

function getKey(header, callback) {
    client.getSigningKey(header.kid, (err, key) => {
        if (err) {
            return callback(err);
        }
        const signingKey = key.publicKey || key.rsaPublicKey;
        callback(null, signingKey);
    });
}

const app = express();

const validateToken = (req, res, next) => {
    const authHeader = req.headers.authorization;
    if (!authHeader) {
        return res.status(401).json({ error: 'No token provided' });
    }

    const token = authHeader.split(' ')[1];

    jwt.verify(token, getKey, (err, decodedToken) => {
        if (err) {
            return res.status(401).json({ error: 'Invalid token' });
        }
        req.user = decodedToken;
        next();
    });
};

app.use('/api/protected', validateToken);

These examples demonstrate how to set up token validation for different frameworks. Next, explore libraries that simplify this process.

Code Libraries

Here are some libraries that can help with token validation:

Framework Library Key Features
Spring Boot spring-boot-starter-oauth2-resource-server Built-in JWT validation and role mapping
Express.js jsonwebtoken + jwks-rsa Automatic key rotation and caching
Django django-oauth-toolkit Token introspection and scope validation
FastAPI python-jose + fastapi-keycloak Async validation and role-based access

Using these tools can save time and ensure reliable token validation across your APIs.

Performance Tips

Boost the efficiency of your token validation with these strategies:

  • Caching Public Keys
    Reduce external calls by caching the JWKS response:

    @Bean
    public JwtDecoder jwtDecoder() {
        NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder
            .withJwkSetUri(jwkSetUri)
            .cache(new MappingJwkSetCache())
            .build();
        return jwtDecoder;
    }
    
  • Parallel Validation
    Handle token validation concurrently for high-traffic APIs:

    @Async
    public CompletableFuture<Boolean> validateTokenAsync(String token) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                jwtDecoder.decode(token);
                return true;
            } catch (JwtException e) {
                return false;
            }
        });
    }
    
  • Load Balancing
    When using Skycloak’s managed service, distribute validation requests effectively. Configure timeouts and monitor metrics like validation time, cache hit ratio, and error rate:

    spring:
      security:
        oauth2:
          resourceserver:
            jwt:
              jwk-set-uri: ${KEYCLOAK_JWKS_URI}
              connection-timeout: 2000
              read-timeout: 2000
    

    For added reliability, implement circuit breakers to handle failures gracefully:

    @CircuitBreaker(name = "tokenValidation", fallbackMethod = "fallbackValidation")
    public boolean validateToken(String token) {
        // Token validation logic
    }
    
    public boolean fallbackValidation(String token, Exception e) {
        log.error("Token validation failed", e);
        return false;
    }
    

These tips can help maintain performance and reliability, even under heavy API traffic.

Token Management

Managing tokens properly is key to keeping APIs secure. This section outlines how to handle the token lifecycle in Keycloak, covering revocation, expiration, and usage tracking.

Revoking Tokens

Revoking tokens ensures they can’t be used after a breach. A token blacklist can help by storing revoked tokens and notifying resource servers:

@Service
public class TokenRevocationService {
    private final KeycloakTokenStore tokenStore;

    public void revokeToken(String tokenId) {
        // Add token to blacklist
        tokenStore.blacklistToken(tokenId);

        // Notify all resource servers of the revocation
        notifyRevocation(tokenId);
    }

    public boolean isTokenRevoked(String tokenId) {
        return tokenStore.isBlacklisted(tokenId);
    }
}

For distributed systems, Redis is a good option for maintaining a shared revocation list:

@Configuration
public class RevocationConfig {
    @Bean
    public RedisTemplate<String, String> redisTemplate() {
        RedisTemplate<String, String> template = new RedisTemplate<>();
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new StringRedisSerializer());
        return template;
    }
}

Setting token lifetimes is another step to secure your APIs.

Token Expiration

Using short-lived tokens with refresh rotation adds an extra layer of security. Below are recommended lifetimes for different token types:

Token Type Recommended Lifetime Use Case
Access Token 5–15 minutes API requests
Refresh Token 24–48 hours Token renewal
ID Token 1 hour User details

Here’s an example configuration for token lifetimes:

token-settings:
  access-token-lifespan: PT15M
  refresh-token-lifespan: P2D
  offline-session-idle-timeout: P30D

For handling refresh tokens, you can use a service like this:

@Service
public class TokenRefreshService {
    public TokenResponse refreshAccessToken(String refreshToken) {
        try {
            // Validate the refresh token
            if (isTokenExpired(refreshToken)) {
                throw new TokenExpiredException();
            }

            // Generate a new access token
            String newAccessToken = generateAccessToken();

            // Rotate the refresh token
            String newRefreshToken = rotateRefreshToken(refreshToken);

            return new TokenResponse(newAccessToken, newRefreshToken);
        } catch (Exception e) {
            throw new AuthenticationException("Token refresh failed");
        }
    }
}

Token Usage Tracking

Once token lifetimes are set, keeping an eye on token usage helps detect potential threats. You can track usage with AOP:

@Aspect
@Component
public class TokenUsageTracker {
    private final MetricsRegistry metricsRegistry;

    @Around("@annotation(RequiresToken)")
    public Object trackTokenUsage(ProceedingJoinPoint joinPoint) throws Throwable {
        String tokenId = extractTokenId(joinPoint);

        Map<String, Object> usageData = new HashMap<>();
        usageData.put("endpoint", joinPoint.getSignature().getName());
        usageData.put("timestamp", Instant.now());
        usageData.put("ipAddress", getCurrentIpAddress());

        metricsRegistry.recordTokenUsage(tokenId, usageData);

        return joinPoint.proceed();
    }
}

Set up alerts to act on suspicious activity:

monitoring:
  alerts:
    - type: token_reuse
      threshold: 5
      window: PT1M
      action: NOTIFY_ADMIN
    - type: concurrent_usage
      threshold: 3
      window: PT5M
      action: REVOKE_TOKEN

Key metrics to track include:

Metric Purpose Alert Threshold
Usage Frequency Spot unusual activity >100 requests/minute
Geographic Distribution Detect suspicious locations >3 countries/hour
Error Rates Monitor failed attempts >20% failure rate
Concurrent Usage Prevent token sharing >2 simultaneous uses

For real-time monitoring, you can use a scheduled task:

@Component
public class RealTimeMonitor {
    @Scheduled(fixedRate = 1000)
    public void checkTokenUsage() {
        List<TokenUsage> suspicious = tokenUsageRepository.findSuspiciousPatterns(
            Duration.ofMinutes(5),
            10,
            3
        );

        if (!suspicious.isEmpty()) {
            notifySecurityTeam(suspicious);
        }
    }
}

Consider using Skycloak to simplify setup and monitoring while reinforcing your API security.

Conclusion

Validating secure tokens with Keycloak plays a crucial role in maintaining robust API security. By using public key verification and introspection, you can ensure that only authenticated requests make it to your backend. Managing token lifecycles – through strict expiration policies and prompt revocation – strikes the right balance between security and usability.

Skycloak provides managed Keycloak services designed to simplify identity and access management (IAM), reduce operational complexity, and align with high-level security requirements.

FAQs

How does Keycloak’s token introspection support real-time revocation, and what are the potential performance trade-offs?

Keycloak’s token introspection allows APIs to verify the validity of an access token in real time by querying the Keycloak server. This ensures that revoked tokens or those that have expired are immediately identified, enhancing security by preventing unauthorized access.

However, real-time introspection can introduce performance overhead, especially in high-traffic scenarios, as each API request may require a call to the Keycloak server. To mitigate this, consider caching token validation results for short durations or using offline validation methods when appropriate, depending on your application’s security and performance needs.

What are the best practices for setting token lifetimes in Keycloak to improve API security?

Token lifetimes play a critical role in balancing security and usability for APIs. Shorter token lifetimes enhance security by reducing the window of opportunity for misuse if a token is compromised. For example, access tokens are typically set to expire within 5 to 15 minutes, ensuring minimal exposure. On the other hand, refresh tokens can have longer lifetimes, such as several hours or days, to allow users to obtain new access tokens without needing to log in again.

When configuring token lifetimes in Keycloak, consider the sensitivity of your API and the user experience. For highly sensitive systems, shorter lifetimes and stricter refresh policies are recommended. However, for less critical applications, slightly longer durations may provide a better balance between security and convenience. Always monitor token usage and adjust settings as needed to address potential risks.

How do I validate Keycloak tokens in a Spring Boot or Express.js application?

To validate Keycloak tokens in your Spring Boot or Express.js application, you need to integrate Keycloak’s authentication mechanisms into your app. This typically involves configuring your application to accept and verify Keycloak-issued tokens.

In Spring Boot, you can use the spring-boot-starter-oauth2-resource-server library to handle token validation. Configure your application properties with Keycloak’s authorization server URL and public key. Once set up, the library will automatically validate incoming tokens and enforce security rules.

For Express.js, you can use middleware like keycloak-connect or libraries such as jsonwebtoken to validate tokens. Set up your Keycloak client, retrieve the public key from the Keycloak server, and verify the token’s signature and claims in your middleware.

For a seamless and enterprise-ready solution, consider using a fully managed IAM platform like Skycloak, which simplifies Keycloak integration and token validation with pre-built configurations and advanced tools.

Related posts

Leave a Comment

Β© 2025 All Rights Reserved. Made by Yasser