PingOne Recognize

Mobile SDK JWT Signing

PingOne Recognize Mobile SDK can generate a signed JWT containing a custom payload. You can use the signed JWT to implement Dynamic Linking.

Generate Signed JWT

Pass JwtSigningInfo to the authentication configuration to generate a signed JWT.

Android

// {p1recognize} adds a td claim to the JWTs containing the data you specify
val jwtSigningInfo = JwtSigningInfo(claimTransactionData = "<your custom data>")

// If you want to authenticate with biometric
val biomAuthConfig = BiomAuthConfig(jwtSigningInfo = jwtSigningInfo)
// If you want to authenticate with pin
val pinAuthConfig = PinAuthConfig(pin = "1234", jwtSigningInfo = jwtSigningInfo)

// Perform the authentication
Keyless.authenticate(
    configuration = biomAuthConfig, // pinAuthConfig if you use pin
    onCompletion = { /* TODO: process result */ }
)

iOS

// {p1recognize} adds a td claim to the JWTs containing the data you specify
let jwtSigningInfo = JwtSigningInfo(claimTransactionData: "<your custom data>")

// If you want to authenticate with biometric
let biomAuthConfig = BiomAuthConfig(jwtSigningInfo: jwtSigningInfo)
// If you want to authenticate with pin
let pinAuthConfig = PinAuthConfig(pin: "1234", jwtSigningInfo: jwtSigningInfo)

// Perform the authentication
Keyless.authenticate(
    configuration: biomAuthConfig, // pinAuthConfig if you use pin
    onCompletion: { /* TODO: process result */ }
)

Flutter

import 'package:keyless_flutter_sdk/keyless.dart';
import 'package:keyless_flutter_sdk/models/jwt_signing_info.dart';
import 'package:keyless_flutter_sdk/models/configurations/authentication_configuration.dart';

// {p1recognize} adds a td claim to the JWTs containing the data you specify
final jwtSigningInfo = JwtSigningInfo("<your custom data>");

// If you want to authenticate with biometric
final biomAuthConfig = BiomAuthConfig(
  jwtSigningInfo: jwtSigningInfo,
);

// If you want to authenticate with pin
final pinAuthConfig = PinAuthConfig(
  pin: "1234",
  jwtSigningInfo: jwtSigningInfo,
);

try {
  // Perform the authentication with either biometric or pin config
  final result = await Keyless.instance.authenticate(
    biomAuthConfig, // or pinAuthConfig if you use pin
  );
  print("JWT signed successfully: ${result.signedJwt}");
} catch (error) {
  print("Authentication failed: $error");
}

React Native

// {p1recognize} adds a td claim to the JWTs containing the data you specify
const jwtSigningInfo = new JwtSigningInfo('<your custom data>');

// If you want to authenticate with biometric
const biomAuthConfig = new BiomAuthConfig({
  jwtSigningInfo: jwtSigningInfo,
});

// If you want to authenticate with pin
const pinAuthConfig = new PinAuthConfig({
  pin: '1234',
  jwtSigningInfo: jwtSigningInfo,
});

const result = await Keyless.authenticate(
  biomAuthConfig, // or pinAuthConfig if you use pin
);

result.fold({
  onSuccess(data) {
    logConsole('Auth result success ' + JSON.stringify(data, null, 2));
  },
  onFailure(error) {
    logConsole('Auth result failure ' + JSON.stringify(error, null, 2));
  },
});

User Signing Public Key

AuthenticationSuccess contains the following field:

  • signedJwt: the signed JWT.

JWT Verification Best Practice

Follow best practice when implementing JWT verification. This also allows KMS key rotation and improves SaaS platform resilience (for example, active/active implementations).

Where to Download the PingOne Recognize jwks.json Endpoint

The endpoint for downloading jwks.json is:

This example uses api.keyless.io as the Operation Service URL and keyless as the customer name. Replace the customer name with your tenant name and use the correct regional Operation Service URL listed here.

The Verification Process

  1. Extract the Header: Parse the JWT header (unverified) to retrieve kid (Key ID) and alg (algorithm).

  2. Lookup the Key: Search the cached jwks.json for a key where kid matches the JWT header. Confirm use is sig and alg matches your expected security profile (for example, RS256).

  3. Construct Public Key: Convert JWK components (for RSA: n modulus and e exponent) into a PEM-formatted public key.

  4. Validate Signature: Use the reconstructed public key to verify the JWT cryptographic signature and check standard claims (exp, iat, iss).

Handling Key Rotation

To prevent authentication failures when keys rotate, implement the following validation logic:

  1. Caching with Refresh: Maintain an in-memory cache of the JWKS and set a standard TTL (for example, 24 hours).

  2. Lazy Refresh on kid Mismatch: If a JWT arrives with a kid not present in the current cache, perform an immediate one-time fetch of jwks.json to check if a new key is published.

  3. Rate Limiting: Limit on-demand JWKS fetches (for example, once every 5 minutes) to prevent abuse from random kid token spam (DoS risk).

  4. Graceful Overlap: Ensure verification logic handles multiple keys in the keys array simultaneously. During rotation, providers publish both old and new keys; trust any currently valid key in the set.