Skip to content

Authzen Interop Writeup

Michael Schwartz edited this page Dec 5, 2025 · 2 revisions

Gluu AuthZen IdP Demo – Technical Write-Up

1. Overview & Goals

Purpose:
Demonstrate how Gluu Flex acts as an Identity Provider (IdP) that calls a compliant AuthZen PDP during token issuance, enriching the issued token with claims returned by the PDP.

Interop scenario reference:
The demo aligns with the AuthZen IdP interop scenario, where the IdP uses AuthZen’s Search API during the authentication flow to decide which claims a user should be granted, then embeds those claims into the ID token. Sample Data

What this demo shows:

  • Gluu Flex extensibility (custom scripts)
  • How Flex makes an AuthZen-compliant call
  • How PDP results drive claim enrichment
  • How the enriched token is consumed by a demo RP

2. Architecture

High-Level Flow

  1. User → Flex Server
    User initiates an OIDC login against Gluu.

  2. Gluu Authentication Flow
    A custom Gluu script executes after authentication but before token issuance:

    • Extracts user identity
    • Calls AuthZen PDP Search API
    • Receives allowed resources/claims
    • Inserts them into JWT
  3. Token Issuance
    Gluu issues an ID token containing the enriched claims.

  4. Demo App / RP
    A relying party processes the token and displays the enriched claims.


3. Gluu Setup – Components

3.1 Enable Custom Script / Passport

Gluu supports custom “person authentication scripts.”
Steps (via Admin UI):

  • Navigate to Scripts
  • Create an Update Token script
  • Insert the AuthZen integration logic

3.2 AuthZen IdP Script

This script:

  1. Extracts authenticated user context and retrieves username
  2. Builds AuthZen-style Search API request
  3. Sends request to the PDP
  4. Parses PDP response
  5. Maps the result array of the response to the record claim
  6. Injects mapped claims into token

3.3 Register OIDC Client

In Auth Server → Clients:

  • Create a client for the demo RP
  • Configure redirect URIs (https://sts.authzen-interop.net/idp/jans/callback)
  • Add scopes (openid, profile, role)
  • Enable appropriate grant and response types (authorization_code)
  • Go to Client Scripts and associate the Update Token field with the script created in the previous step

3.4 PDP Integration

  • Obtain PDP endpoint URL for the vendor participating
  • Insert the URL into the script via config variable

4. Demo App / How to Test

4.1 Demo RP

You may use the AuthZen interop demo application

4.2 User Flow

  1. User logs into the RP → redirected to Flex
  2. Flex authenticates the user
  3. AuthZen script triggers
  4. Flex requests resources from PDP
  5. PDP returns resource/claim list
  6. Flex enriches token and issues it
  7. RP decodes the token and displays enriched claims

5. Demo Narrative (Suggested Flow)

  1. Intro: “Gluu is acting as an AuthZen-enabled IdP. During login, it queries a PDP to determine which claims to include.”
  2. Show Script: Display the custom AuthZen script configuration in Admin UI (search for authzen_interop under Update Token)
  3. Login: Run the login flow in the demo RP.
  4. Token Inspection: Decode the JWT to show enriched claims.
  5. PDP Swap: Switch to a different vendor PDP and repeat — demonstrating interoperability.

Custom script:

from io.jans.model.custom.script.type.token import UpdateTokenType
from io.jans.service.cdi.util import CdiUtil
from io.jans.as.server.service import SessionIdService
from io.jans.as.server.model.config import ConfigurationFactory
from io.jans.as.server.service import ClientService
from io.jans.as.server.service.net import HttpService
from java.nio.charset import Charset
from org.json import JSONObject
import json

class UpdateToken(UpdateTokenType):
    def __init__(self, currentTimeMillis):
        self.currentTimeMillis = currentTimeMillis

    def init(self, customScript, configurationAttributes):
        print "AuthZen interop script. Initializing ..."
        if (not configurationAttributes.containsKey("PDP_URL")):
            print "AuthZen interop script. Property PDP_URL is not specified"
            return False
        self.PDP_URL = configurationAttributes.get("PDP_URL").getValue2()
        httpService = CdiUtil.bean(HttpService)
        self.http_client = httpService.getHttpsClient()
        print "AuthZen interop script. Initialized successfully"

        return True

    def destroy(self, configurationAttributes):
        print "AuthZen interop script. Destroying ..."
        print "AuthZen interop script. Destroyed successfully"
        return True

    def getApiVersion(self):
        return 11

    def modifyIdToken(self, jsonWebResponse, context):
        print "Authzen Interop script. Modify idToken: %s" % jsonWebResponse
        sessionIdService = CdiUtil.bean(SessionIdService)
        sessionId = sessionIdService.getSessionByDn(context.getGrant().getSessionDn()) 
        uid = sessionId.getSessionAttributes().get("auth_user")
        url = self.PDP_URL + "/access/v1/search/resource"
        body = {
              "subject": {
                "type": "user",
                "id": uid 
              },
              "action": {
                "name": "delete"
              },
              "resource": {
                "type": "record"
              }
        }
        body_json = json.dumps(body)
        request_headers = { "Content-type" : "application/json; charset=UTF-8", "Accept" : "application/json" }
        try:
            httpService = CdiUtil.bean(HttpService)
            # call demo app's PDP search endpoint
            http_service_response = httpService.executePost(self.http_client, url, None, request_headers, body_json)
            http_response = http_service_response.getHttpResponse()
            response_bytes = httpService.getResponseContent(http_response)
            response_string = httpService.convertEntityToString(response_bytes, Charset.forName("UTF-8"))
            if not httpService.isResponseStastusCodeOk(http_response):
                print "Authzen Interop Script. PDP returned %s" % str(http_response.getStatusLine().getStatusCode())
                return False
            json_response = JSONObject(response_string)
            httpService.consume(http_response)
            http_service_response.closeConnection()
        except:
            print "Authzen Interop Script. Exception: %s ", sys.exc_info()[1]
            return False

        # parse results array into record claim
        jsonWebResponse.getClaims().setClaim("record", json_response.getJSONArray("results"))

        print "Update token script. After modify idToken: %s" % jsonWebResponse
        return True


    def modifyRefreshToken(self, refreshToken, context):
        return True

    def modifyAccessToken(self, accessToken, context):
        return True

    def getRefreshTokenLifetimeInSeconds(self, context):
        return 0

    def getIdTokenLifetimeInSeconds(self, context):
        return 0

    def getAccessTokenLifetimeInSeconds(self, context):
        return 0

Clone this wiki locally