Code samples to verify the redirect

The following guide contains code samples in NodeJS, Python, and Java that can be used to verify the parameters in the redirect.

All of the code samples on this page assume that the user's session id is stored in browser cookies (Secure, HttpOnly, and SameSite=Strict). Therefore, the session id will be easily available to the backend server because the browser will send the cookies in redirect request.

data-slots=text
Note: Always verify the state, nonce, and signature of the ID token on the backend. Do not expose this logic client-side.

NodeJS

Install NodeJS packages

npm install jsonwebtoken axios jose

Verify the redirect - NodeJS

const axios = require('axios');
const { jwtVerify, importJWK } = require('jose');

/**
 * Verifies:
 * 1. session.state === state
 * 2. id token is valid
 * 3. session.nonce === payload.nonce
 *
 * Returns org_id from token if valid
 *
 * @param {string} idToken - The id_token from the redirect
 * @param {object} session - Contains expected `state` and `nonce`
 * @param {string} state - State from the redirect
 * @returns {Promise<string>} - org_id claim from the id_token
 */
async function verifyRedirect(idToken, session, state) {
  // Step 1: State check
  if (session.state !== state) {
    throw new Error('State mismatch');
  }

  // Step 2: Decode header to get kid
  const decodedHeader = JSON.parse(Buffer.from(idToken.split('.')[0], 'base64').toString());
  if (!decodedHeader?.kid) {
    throw new Error('Invalid id token: missing kid');
  }

  const kid = decodedHeader.kid;

  // Step 3: Fetch JWKS and get matching key
  const keys = await fetchAdobeKeys();

  const jwk = keys.find(k => k.kid === kid);
  if (!jwk) {
    throw new Error(`No matching JWK found for kid: ${kid}`);
  }

  // Step 4: Import JWK and verify token
  const publicKey = await importJWK(jwk, jwk.alg);
  const { payload } = await jwtVerify(idToken, publicKey, {
    algorithms: ['RS256'],
  });

  // Step 6: Nonce check
  if (session.nonce !== payload.nonce) {
    throw new Error('Nonce mismatch');
  }

  // Step 7: Return org_id
  if (!payload.orgId) {
    throw new Error('org_id claim missing in id_token');
  }

  return payload.orgId;
}

/**
 * Fetch Adobe IMS public keys (JWKS)
 */
async function fetchAdobeKeys() {
  const response = await axios.get('https://ims-na1.adobelogin.com/ims/keys');
  return response.data.keys;
}



// Example usage
(async () => {
  const idToken = 'your.id.token.here';
  const session = {
    state: 'xyz123',
    nonce: 'abc456'
  };
  const state = 'xyz123';

  try {
    const orgId = await verifyRedirect(idToken, session, state);
    console.log('Verified org_id:', orgId);
  } catch (err) {
    console.error('Redirect verification failed:', err.message);
  }
})();

Python

Install Python packages

pip install pyjwt requests cryptography

Verify the redirect - Python

import requests
import jwt
from jwt import PyJWKClient

ADOBE_JWKS_URL = "https://ims-na1.adobelogin.com/ims/keys"

def verify_redirect(id_token: str, session: dict, state: str, client_id: str) -> str:
  """
  Verifies:
  1. session.state == state
  2. id token is valid via Adobe public keys
  3. session.nonce == token's nonce
  4. Returns org_id from the token if all checks pass

  :param id_token: The id_token returned from the redirect
  :param session: Dict with 'state' and 'nonce' keys
  :param state: The 'state' query parameter from redirect
  :return: org_id claim from the id_token
  :raises RedirectVerificationError: on any failure
  """

  # Step 1: Check state
  if session.get('state') != state:
    raise RedirectVerificationError("State mismatch")

  # Step 2: Load signing key using PyJWKClient
  try:
    jwk_client = PyJWKClient(ADOBE_JWKS_URL)
    signing_key = jwk_client.get_signing_key_from_jwt(id_token)
  except Exception as e:
    raise RedirectVerificationError(f"JWK retrieval/lookup failed: {e}")

  # Step 3: Verify id_token signature
  try:
    decoded = jwt.decode(
      id_token,
      signing_key.key,
      audience=client_id,
      algorithms=["RS256"]
    )
  except jwt.PyJWTError as e:
    raise RedirectVerificationError(f"id token verification failed: {e}")

  # Step 4: Nonce check
  if session.get('nonce') != decoded.get('nonce'):
    raise RedirectVerificationError("Nonce mismatch")

  # Step 5: Return org_id
  org_id = decoded.get('orgId')
  if not org_id:
    raise RedirectVerificationError("orgId claim missing in token")

  return org_id

class RedirectVerificationError(Exception):
  pass

# Example usage
if __name__ == "__main__":
  id_token = "your.id.token.here"
  session = {
    "state": "xyz123",
    "nonce": "abc456"
  }
  state = "xyz123"
  client_id = "your.application.client.id"

  try:
    org_id = verify_redirect(id_token, session, state, client_id)
    print("Verified org_id:", org_id)
  except RedirectVerificationError as e:
    print("Redirect verification failed:", e)

Java

Add these dependencies to your pom.xml

<dependencies>
  <dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>4.4.0</version>
  </dependency>
  <dependency>
    <groupId>com.auth0</groupId>
    <artifactId>jwks-rsa</artifactId>
    <version>0.22.0</version>
  </dependency>
</dependencies>

Verify the redirect - Java

import com.auth0.jwk.Jwk;
import com.auth0.jwk.JwkProvider;
import com.auth0.jwk.UrlJwkProvider;
import com.auth0.jwt.JWT;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;

import java.net.URL;
import java.security.interfaces.RSAPublicKey;
import java.util.Map;

public class VerifyRedirect {

    private static final String JWKS_URL = "https://ims-na1.adobelogin.com/ims/keys";

    /**
     * Verifies that:
     * 1. session.state equals the redirect state
     * 2. The JWT is valid using Adobe's public key
     * 3. session.nonce matches the nonce in the JWT
     * 
     * @param idToken The id token from the redirect URL
     * @param session Map containing "state" and "nonce"
     * @param state The state parameter from the redirect URL
     * @return The org_id claim if verification succeeds
     * @throws Exception if verification fails
     */
    public static String verifyRedirect(String idToken, Map<String, String> session, String state) throws Exception {
        // Step 1: Check state
        if (!state.equals(session.get("state"))) {
            throw new Exception("State mismatch");
        }

        // Step 2: Decode id token to get the kid
        DecodedJWT decodedJWT = JWT.decode(idToken);
        String kid = decodedJWT.getKeyId();

        // Step 3: Get the JWK matching the kid
        JwkProvider provider = new UrlJwkProvider(new URL(JWKS_URL));
        Jwk jwk = provider.get(kid);
        RSAPublicKey publicKey = (RSAPublicKey) jwk.getPublicKey();

        // Step 4: Validate the id token
        Algorithm algorithm = Algorithm.RSA256(publicKey, null);
        JWTVerifier verifier = JWT.require(algorithm).build();
        DecodedJWT verifiedJwt = verifier.verify(idToken);

        // Step 5: Check nonce
        String tokenNonce = verifiedJwt.getClaim("nonce").asString();
        if (!session.get("nonce").equals(tokenNonce)) {
            throw new Exception("Nonce mismatch");
        }

        // Step 6: Return org_id
        String orgId = verifiedJwt.getClaim("orgId").asString();
        if (orgId == null || orgId.isEmpty()) {
            throw new Exception("orgId claim missing in token");
        }

        return orgId;
    }

    // Example usage
    public static void main(String[] args) {
        String idToken = "your.jwt.token.here";
        Map<String, String> session = Map.of(
            "state", "xyz123",
            "nonce", "abc456"
        );
        String state = "xyz123";

        try {
            String orgId = verifyRedirect(idToken, session, state);
            System.out.println("Verified org_id: " + orgId);
        } catch (Exception e) {
            System.err.println("Redirect verification failed: " + e.getMessage());
        }
    }
}