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
-
Extract the Header: Parse the JWT header (unverified) to retrieve
kid(Key ID) andalg(algorithm). -
Lookup the Key: Search the cached
jwks.jsonfor a key wherekidmatches the JWT header. Confirmuseissigandalgmatches your expected security profile (for example,RS256). -
Construct Public Key: Convert JWK components (for RSA:
nmodulus andeexponent) into a PEM-formatted public key. -
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:
-
Caching with Refresh: Maintain an in-memory cache of the JWKS and set a standard TTL (for example, 24 hours).
-
Lazy Refresh on
kidMismatch: If a JWT arrives with akidnot present in the current cache, perform an immediate one-time fetch ofjwks.jsonto check if a new key is published. -
Rate Limiting: Limit on-demand JWKS fetches (for example, once every 5 minutes) to prevent abuse from random
kidtoken spam (DoS risk). -
Graceful Overlap: Ensure verification logic handles multiple keys in the
keysarray simultaneously. During rotation, providers publish both old and new keys; trust any currently valid key in the set.