Pyxis Logo
Home / IBM Training / Technical article

Db2 11.5 token-based authentication in practice

A hands-on lab that configures token authentication with a local issuer, db2token.cfg, and CLP and JDBC examples.

15 min read
Published 2026-05-10
Pyxis editorial team
Rate this article
Average rating: Not rated
Your rating: Not rated
visualizations: 0
Abstract technical operations background

Token authentication in Db2, introduced in 11.5.4, lets a client connect with a token instead of a password. This is useful in SSO-style integrations and application flows where identity has already been established upstream.

This article is deliberately practical. Every step below shows the exact files to create, the commands to run, and the checks to perform. The lab is designed to be reproduced on a Linux machine with a Db2 instance.

Authentication in Db2

Before addressing token authentication, it is helpful to list the important security aspects for Db2:

  • Authentication validates and establishes identity
  • Authorization determines what is permitted under a given identity
  • Connection setup is the handshake that carries both the credentials and the security policy

In a classic Db2 connection, the client provides a username and password, Db2 validates them, and the resulting Authorization ID becomes the identity for the session. Token authentication changes the first step: instead of a password, the client provides a signed token to prove its identity.

That difference has important operational impacts. The application no longer has to manage the password. Instead, Db2 validates a token issued and signed on another system and then maps one of the token claims to the Db2 authid used by the session.

The way authorizations are validated remains unchanged. Db2 continues to apply privileges, roles, and database and instance administrative authorities to the identity that was established.

JWT

A JSON Web Token (JWT) is a compact way to carry claims about an identity and sign them so the receiver can trust the contents.

The JWT has three parts:

  • a header, which describes the signing algorithm
  • a payload, which carries claims such as issuer, subject, and expiration
  • a signature, which proves the token was signed by a trusted entity

For this lab, the important claims are:

  • iss, which identifies the issuer
  • username, which we map to the Db2 authid
  • iat, which tells you when the token was created
  • exp, which tells you when the token stops being valid

Db2 only needs enough of the JWT structure to trust the issuer, extract the mapped claim, and reject expired or malformed tokens. That is why the rest of the article uses a simple signed JWT instead of a full identity platform.

What this lab builds

By the end of the lab you will have:

  • a local key pair for signing JWTs
  • a PKCS#12 keystore containing the issuer certificate for Db2 validation
  • a db2token.cfg file that trusts the issuer and maps a claim to the Db2 authid
  • Db2 configured to accept token-based server connections
  • a database that accepts a token-based CLP connection
  • a JDBC example that uses the same token
  • a repeatable failure test for invalid or expired tokens

Prerequisites

Use a Db2 server at version 11.5.4 or later.

You also need:

  • shell access to the Db2 instance owner account
  • openssl
  • gsk8capicmd_64
  • the Db2 CLP
  • a Java runtime and the Db2 JDBC driver if you want to run the Java example

1. Create the issuer key pair

The issuer is the system that signs the JWT. For the lab we keep it local so the flow is easy to reproduce.

Log in as the Db2 instance owner, create a working directory, and generate a 3072-bit RSA key:

mkdir -p "$HOME/db2-token-lab"
cd "$HOME/db2-token-lab"
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:3072 -out jwt-issuer.key

Create a self-signed certificate from that key:

openssl req -new -x509 \
  -key jwt-issuer.key \
  -out jwt-issuer.crt \
  -days 365 \
  -subj "/CN=PYXIS-ISSUER/O=Pyxis/L=Lisbon/C=PT"

The certificate subject is not the JWT issuer string. It is simply the certificate identity that Db2 will trust.

2. Create the keystore Db2 will use

Db2 needs a local PKCS#12 keystore containing the issuer certificate.

Create the keystore:

gsk8capicmd_64 -keydb -create \
  -db "$HOME/db2-token-lab/jwtkeys.p12" \
  -pw "Db2Token123!" \
  -stash

Import the issuer certificate into that keystore with a label that we will reference later:

gsk8capicmd_64 -cert -add \
  -db "$HOME/db2-token-lab/jwtkeys.p12" \
  -pw "Db2Token123!" \
  -label db2jwt \
  -file "$HOME/db2-token-lab/jwt-issuer.crt" \
  -format ascii

Check the label if you want to confirm it was stored correctly:

gsk8capicmd_64 -cert -list \
  -db "$HOME/db2-token-lab/jwtkeys.p12" \
  -pw "Db2Token123!"

Db2 will use this keystore to validate the JWT signature.

3. Create db2token.cfg

Now, create the token configuration file in the instance config directory:

cat > "$HOME/sqllib/cfg/db2token.cfg" <<EOF
VERSION=1
TOKEN_TYPES_SUPPORTED=JWT
JWT_KEYDB=$HOME/db2-token-lab/jwtkeys.p12
JWT_IDP_ISSUER=PYXIS-ISSUER
JWT_IDP_AUTHID_CLAIM=username
JWT_IDP_RSA_CERTIFICATE_LABEL=db2jwt
EOF
chmod 600 "$HOME/sqllib/cfg/db2token.cfg"

What each line does:

  • VERSION=1 declares the configuration file format
  • TOKEN_TYPES_SUPPORTED=JWT tells Db2 that JWT tokens are allowed
  • JWT_KEYDB points to the local keystore
  • JWT_IDP_ISSUER must match the JWT iss claim exactly
  • JWT_IDP_AUTHID_CLAIM tells Db2 which claim contains the authid
  • JWT_IDP_RSA_CERTIFICATE_LABEL identifies the certificate in the keystore

Verify the file:

cat "$HOME/sqllib/cfg/db2token.cfg"

4. Enable token authentication on the server

If the instance is not already using TCP/IP, enable the protocol now by configuring the DB2COMM Registry variable:

db2set DB2COMM=TCPIP

Set the server connection authentication mode to token-based encryption:

db2 update dbm cfg using srvcon_auth SERVER_ENCRYPT_TOKEN

Restart the instance so the new configuration is applied:

db2stop force
db2start

Confirm the parameter after restart:

db2 get dbm cfg | egrep -i "svcename|srvcon_auth"

Determine the actual TCP port that Db2 is listening on. We will store the value in the DB2_PORT environment variable:

SVCENAME=$(db2 get dbm cfg | awk -F= '/TCP\/IP Service name/ {gsub(/[[:space:]]/, "", $2); print $2}')

if [[ "$SVCENAME" =~ ^[0-9]+$ ]]; then
  DB2_PORT="$SVCENAME"
else
  DB2_PORT=$(awk -v svc="$SVCENAME" '$1 == svc && $2 ~ /tcp/ {split($2, a, "/"); print a[1]; exit}' /etc/services)
fi

echo "$DB2_PORT"
ss -ltn | grep "$DB2_PORT"

If DB2_PORT comes back empty, the service name from svcename is not mapped in /etc/services and JDBC will still not know which port to use.

5. Create a test database

Create a database for the demo:

db2 create database TOKDB

Connect once to confirm the database is available and grant connect to the DEMO1 user:

db2 connect to TOKDB
db2 "grant connect on database to user DEMO1"
db2 connect reset
db2 terminate

6. Generate a signed JWT

The token needs to contain at least:

  • iss matching the issuer name in db2token.cfg
  • a claim that maps to the authid
  • an issued-at time
  • an expiry time

Save the following script as make-jwt.sh in the lab directory:

#!/usr/bin/env bash
set -euo pipefail

if [ "$#" -lt 4 ]; then
  echo "Usage: $0 <private-key> <issuer> <authid> <ttl-seconds>" >&2
  exit 1
fi

key_file="$1"
issuer="$2"
authid="$3"
ttl_seconds="$4"

now=$(date +%s)
exp=$((now + ttl_seconds))

header='{"alg":"RS256","typ":"JWT"}'
payload=$(printf '{"username":"%s","sub":"%s","iss":"%s","iat":%s,"exp":%s}' \
  "$authid" "$authid" "$issuer" "$now" "$exp")

b64url() {
  openssl base64 -A | tr '+/' '-_' | tr -d '='
}

header_b64=$(printf '%s' "$header" | b64url)
payload_b64=$(printf '%s' "$payload" | b64url)
unsigned_token="${header_b64}.${payload_b64}"

signature_b64=$(printf '%s' "$unsigned_token" \
  | openssl dgst -sha256 -sign "$key_file" -binary \
  | b64url)

printf '%s.%s\n' "$unsigned_token" "$signature_b64"

Make it executable:

chmod +x make-jwt.sh

Generate a token for the DEMO1 authid with a one-hour lifetime:

./make-jwt.sh "$HOME/db2-token-lab/jwt-issuer.key" PYXIS-ISSUER DEMO1 3600 > token.jwt

Inspect the token file:

TOKEN=$(cat token.jwt)
base64 -d <<< $(echo $TOKEN | cut -d'.' -f1 | tr '_-' '/+')
base64 -d <<< $(echo $TOKEN | cut -d'.' -f2 | tr '_-' '/+')

The username claim is important because db2token.cfg maps that claim to the Db2 authorization ID.

7. Connect from the Db2 CLP

Use the token in an explicit CLP connection:

db2 connect to TOKDB accesstoken "$(cat token.jwt)" accesstokentype jwt

If the connection succeeds, validate the mapped identity:

db2 "values current user"

You should see the token-mapped authid in uppercase, which in this demo is DEMO1.

Disconnect and end the CLP session:

db2 connect reset
db2 terminate

8. Connect from JDBC

The JDBC demo shows the token flow from a Java application.

Save the following code as TokenAuthDemo.java:

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;

import com.ibm.db2.jcc.DB2BaseDataSource;
import com.ibm.db2.jcc.DB2SimpleDataSource;

public class TokenAuthDemo {
    public static void main(String[] args) throws Exception {
        if (args.length < 3) {
            throw new IllegalArgumentException("Usage: TokenAuthDemo <jwt> <host> <port>");
        }

        String token = args[0];
        String host = args[1];
        int port = Integer.parseInt(args[2]);

        DB2SimpleDataSource ds = new DB2SimpleDataSource();
        ds.setDriverType(4);
        ds.setServerName(host);
        ds.setPortNumber(port);
        ds.setDatabaseName("TOKDB");
        ds.setLoginTimeout(15);
        ds.setSecurityMechanism(DB2BaseDataSource.TOKEN_SECURITY);
        ds.setAccessToken(token);
        ds.setAccessTokenType("JWT");

        try (Connection conn = ds.getConnection();
             Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery("VALUES CURRENT USER")) {
            while (rs.next()) {
                System.out.println("CURRENT USER = " + rs.getString(1));
            }
        }
    }
}

Compile with the Db2 JDBC driver on the classpath:

javac -cp "$HOME/sqllib/java/db2jcc4.jar" TokenAuthDemo.java

If you see errors such as package com.ibm.db2.jcc does not exist, your classpath is not pointing at the actual Db2 JDBC driver jar. On a typical Db2 server install, db2jcc4.jar is available under $HOME/sqllib/java/.

Run it with the same token:

java -cp ".:$HOME/sqllib/java/db2jcc4.jar" TokenAuthDemo "$(cat token.jwt)" localhost "$DB2_PORT"

If the setup is correct, the program prints the token-mapped user.

The example sets a 15-second login timeout so it fails instead of hanging indefinitely.

If you get Connection refused, Db2 is not listening on the host/port used by JDBC. Check the svcename value, confirm the instance was restarted, resolve the real port, and validate with ss -ltn that the listener is really up.

9. Test with various failure scenarios

We now test with various failure scenarios.

Wrong issuer

Create a token with a different issuer string:

./make-jwt.sh "$HOME/db2-token-lab/jwt-issuer.key" BAD-ISSUER DEMO1 3600 > bad-issuer.jwt
db2 connect to TOKDB accesstoken "$(cat bad-issuer.jwt)" accesstokentype jwt

This should fail because BAD-ISSUER does not match JWT_IDP_ISSUER.

Expired token

Create a token with a negative lifetime:

./make-jwt.sh "$HOME/db2-token-lab/jwt-issuer.key" PYXIS-ISSUER DEMO1 -60 > expired.jwt
db2 connect to TOKDB accesstoken "$(cat expired.jwt)" accesstokentype jwt

This should fail because the token has already expired.

Wrong authid claim

Create a token for another user and try to connect to the database:

./make-jwt.sh "$HOME/db2-token-lab/jwt-issuer.key" PYXIS-ISSUER OTHERUSER 3600 > wrong-user.jwt
db2 connect to TOKDB accesstoken "$(cat wrong-user.jwt)" accesstokentype jwt

The connection fails. It can only succeed if that authid is acceptable in your environment. Otherwise, this is a clear way to show that claim-to-authid mapping matters.

Troubleshooting

If the connection does not work, check first whether:

  • db2token.cfg is in the instance config directory
  • the iss claim matches JWT_IDP_ISSUER
  • the token is signed with the same key as the trusted certificate
  • the token has not expired
  • Db2 is listening on the expected TCP/IP port
  • srvcon_auth is set to SERVER_ENCRYPT_TOKEN
  • the instance was restarted after the changes

If JDBC fails while CLP works, check:

  • the driver version
  • the TOKEN_SECURITY setting
  • the accessTokenType value

Key takeaways

  • Db2 token authentication is available starting with 11.5.4.
  • The server uses db2token.cfg to trust the issuer and map claims to authids.
  • CLP and JDBC can both authenticate with a JWT.

Useful IBM documentation

For deeper reading, the most useful IBM references for this topic are:

More in this area

More in this area

Back to training
Article category

Db2 LUW Articles

Browse all technical articles for Db2 LUW in one category page.

Open category Db2 LUW