DEV Community

DarkEdges
DarkEdges

Posted on

Custom ID-JAG on PingFederate, Part 1: Can PingFederate 12.3.3 Issue an ID-JAG?

PF ID-JAG: Can PingFederate 12.3.3 issue an ID-JAG through a custom token generator?

For the fixed-destination proof described here, the answer is yes. A live PingFederate server returned the assertion, and its signature verified against that server's published JWKS.

That result matters, but so does its boundary. It is not evidence that an arbitrary application can accept the assertion, that a complete Cross-App Access deployment exists, or that the implementation conforms to every requirement of the evolving specification.

This series follows the path from inspecting the extension points to applying Terraform and testing the real token endpoint.

Code for this series: project repository.

What we were trying to build

Cross-App Access, or XAA, is the pattern described by the Identity Assertion JWT Authorization Grant draft. An application obtains an ID-JAG through token exchange, then presents that assertion to a downstream authorization server to request an access token. The draft connects OAuth token exchange with the JWT authorization grant flow. This project uses draft-04 as its reference, not a finalized standard.

Our implementation focuses on the first exchange. The intended sequence is:

  1. The requesting client authenticates to PingFederate and supplies a subject token.
  2. PingFederate validates the token and applies an authorization policy.
  3. A custom generator issues an ID-JAG for a fixed downstream destination.
  4. The application would redeem that assertion at the downstream authorization server.

Only the first three steps were exercised against the live server. Step four remains integration work.

Missing native support was not the same as a missing extension path

An early assumption in this project was that a generic JWT access-token flow would be the practical substitute. That assumption did not survive inspection of the actual 12.3.3 classes.

The relevant question was more precise: could the token-exchange pipeline route a custom requested token type to a token generator and preserve its output?

The Java extension point exposes:

SecurityToken generateToken(TokenContext context)
Enter fullscreen mode Exit fullscreen mode

The server also has token-exchange generator groups and mappings. Ping's generator-group documentation describes associating requested token types with generator instances and routing requests using resource URIs.

We inspected and exercised the request parser, resource selector, generator mapping and response serializer from the actual local installation. That established an offline path worth testing on a running server.

It did not establish a working deployment yet. Client authentication, plugin discovery, attribute mappings and key retrieval still had to work together.

The token processor and generator have different jobs

The implementation uses the built-in JWT Token Processor 2.0 for inbound validation and a custom Java generator for outbound issuance.

The processor validates the configured issuer, signature, audience and time claims. A Token Exchange Processor Policy then restricts the allowed subject and checks the authorized-party claim, azp.

The generator checks the authenticated client, destination, scope and remaining subject-token lifetime before signing the outgoing assertion.

This division is important. Producing a signed JWT does not establish that its subject is authorized to access another application's API. The authorization decision needs a trusted source and an explicit policy.

For the lab, that policy authorizes exactly one test subject. It is intentionally not a substitute for production entitlements.

A deliberately narrow proof

The tested setup has one requesting client, one target authorization-server issuer, one resource, one allowed scope and RS256 signing. Assertion lifetime is capped at 300 seconds and cannot exceed the validated subject token's expiry.

The build uses the PF 12.3.3 installation and SDK. The live Admin API reports version 12.3.3.1.

The inbound token is a locally signed fixture whose public key is explicitly trusted by the JWT processor. That gives us controlled positive and negative tests without pretending to have completed a real OIDC login.

The target issuer and resource use reserved example domains. No downstream authorization server or target client was provisioned by this proof.

What the live result established

The successful response contained the unchanged compact JWT in access_token, the ID-JAG URI in issued_token_type, token_type set to N_A, and a bounded expires_in value.

The runner verified the signature using PingFederate's live JWKS endpoint. It also checked the intended subject, issuer, destination, client, resource and scope.

Across the live run, 27 checks passed. Those included rejection cases, not just successful issuance. The detailed test coverage is the subject of Part 4.

The lesson

There is a useful distinction between a product feature being available out of the box and a product having extension points capable of implementing a constrained version of it.

For this server, the custom-generator path was viable. Getting it to work required understanding the validation that happens before the generator, the attributes that actually reach it and the format the server returns afterward.

Part 2 covers those runtime details, including an audience lookup that initially looked unrelated to the outgoing assertion and a way to avoid expression-based request mappings.

Top comments (0)