Skip to main content

Trust API Bind (TAB) Integration Documentation

1. Android SDK Integration Guide

This guide details how to integrate the zrt-release.jar local SDK into your Android application, generate secure cryptographic tokens, and properly transmit them to protect your critical business infrastructure.

Phase 1: Project Setup & Installation

1. Place the JAR in the Project Directory

First, add the .jar file to your app's local libs directory so it is bundled with the project.

Navigate to your project structure to your Android app module (usually named app). If it doesn't already exist, create a folder named libs inside the app folder. Move zrt-release.jar into this directory.

Expected Structure:

your_project/
├── app/
│ ├── libs/
│ │ └── zrt-release.jar
│ ├── src/
│ └── build.gradle (.kts)

2. Configure Repositories

If you are using modern Android Studio (Android Gradle Plugin 7.0+), dependency repositories are centralized in your settings file. You need to declare the flatDir pointing to the libs directory.

note

In some legacy projects, repositories are defined in the root build.gradle inside allprojects { repositories { ... } }.

Using Kotlin DSL (settings.gradle.kts):

dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
// Define the local library directory
flatDir {
dirs("libs")
}
}
}

Using Groovy (settings.gradle):

dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
// Define the local library directory
flatDir {
dirs 'libs'
}
}
}

3. Add Dependency

Next, declare the JAR file as an implementation dependency in your app-level build configuration (app/build.gradle or app/build.gradle.kts). Follow the explicit file dependency strategy.

Using Kotlin DSL (app/build.gradle.kts):

dependencies {
// Other dependencies...

// Explicitly add the ZRT SDK
implementation(files("libs/zrt-release.jar"))
}

Using Groovy (app/build.gradle):

dependencies {
// Other dependencies...

// Explicitly add the ZRT SDK
implementation files('libs/zrt-release.jar')
}
important

Sync your Gradle files after making these changes.


Phase 2: Generating the Token

Once the Gradle sync completes, you are ready to import and invoke the SDK. The ZeroRootTrust class resides in the com.zrt package and exposes a static method getToken(String parameter).

4. SDK Invocation

Kotlin (MainActivity.kt):

package com.your.package.name

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import com.zrt.ZeroRootTrust

class MainActivity : AppCompatActivity() {
private val TAG = "ZRT-Integration"

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

// Replace with the specific data payload/nonce fetched from your server
val dataPayload = "server_generated_nonce_123"

// Invoke the ZRT SDK function
val zrtToken = ZeroRootTrust.getToken(dataPayload)

Log.d(TAG, "Successfully generated ZRT Token: $zrtToken")
}
}

Java (MainActivity.java):

package com.your.package.name;

import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import com.zrt.ZeroRootTrust;

public class MainActivity extends AppCompatActivity {
private static final String TAG = "ZRT-Integration";

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

// Replace with the specific data payload/nonce fetched from your server
String dataPayload = "server_generated_nonce_123";

// Invoke the ZRT SDK function
String zrtToken = ZeroRootTrust.getToken(dataPayload);

Log.d(TAG, "Successfully generated ZRT Token: " + zrtToken);
}
}

5. Understanding the Cryptographic Nonce

When invoking getToken(), you must pass a string parameter (dataPayload). This acts as a cryptographic nonce (number used once) and plays a critical role in the Zero Root Trust process.

  • Prevention of Replay Attacks: The nonce ensures that every generated token is uniquely tied to a specific session or server request. Malicious actors cannot intercept a valid token and successfully reuse it later, because the outdated nonce bound to that token will be rejected by your backend.
  • Cryptographic Binding: When you pass the nonce into the SDK, it is securely embedded and signed into the generated ZRT token's payload.

Possible Formats for Nonce:

The nonce parameter is flexible and can represent different forms of contextual integrity data depending on your security requirements and backend implementation. Common approaches include:

FormatDescription
Server-Generated NonceA unique, cryptographically secure nonce fetched from your backend for every sensitive request or session.
Checksum of API Request PayloadA checksum generated from the API request body or critical transaction parameters.
Custom Validation StringAny custom string representing data important for integrity verification during testing or implementation.

Best Practices:

  • Dynamic & Unique: Must be generated dynamically by your backend server for each new sensitive action.
  • Unpredictable: Generated using a cryptographically secure random number generator (CSRNG).
  • Time-bound: The server should associate a strict expiration time with the nonce (e.g., 60 seconds).

Phase 3: Transmission & Endpoint Security

6. Transmitting the Token via HTTP Headers

To ensure your backend can seamlessly verify the integrity of the request, do not send the ZRT token in the request body or URL parameters. It must be attached as a standard HTTP Header on your outgoing network requests (e.g., via Retrofit, OkHttp, or Volley).

We recommend using a dedicated custom header to avoid conflicts with standard OAuth/Session tokens:

  • Header Name: X-ZRT-Token
  • Header Value: <the_generated_zrt_token>

Example — OkHttp Interceptor:

val zrtInterceptor = Interceptor { chain ->
val originalRequest = chain.request()

// Generate token dynamically right before the network call
val token = ZeroRootTrust.getToken(currentNonce)

val newRequest = originalRequest.newBuilder()
.header("X-ZRT-Token", token)
.build()

chain.proceed(newRequest)
}

7. Securing Critical Business Logic

A Zero-Trust architecture assumes the client device is inherently compromised. To properly protect your business, you must enforce ZTRB token validation on as many high-risk endpoints as possible.

The Golden Rule

If a specific API endpoint modifies data, moves money, or grants access, it should require a fresh ZTRB token generated using a fresh, server-issued nonce.

Require a fresh nonce and newly generated ZRT token for all of the following:

Authentication & Onboarding

  • Account creation and login endpoints
  • Password resets and MFA verification steps

Financial & Transactional Logic

  • Checkout processing, wallet top-ups, and fund transfers
  • Adding or modifying payment methods

Profile & PII Mutations

  • Updating email addresses, phone numbers, or physical addresses
  • Viewing or exporting sensitive PII data

Core App Economy

  • Claiming rewards, redeeming promo codes, or executing high-value in-app actions

2. iOS Integration Guide

This guide details how to integrate the ZRTAttest.xcframework into your iOS application to enable secure device attestation, generate cryptographic tokens, and properly transmit them to protect your critical business infrastructure.

Phase 1: Project Setup & Installation

Prerequisites

RequirementVersion
Xcode14.0 or later
iOS Deployment Target13.0+
FrameworkZRTAttest.xcframework (provided by Bugsmirror)

1. Add the XCFramework to Your Project

  1. Open your Xcode project.
  2. Drag ZRTAttest.xcframework into the Project Navigator panel (left sidebar).
    • Alternatively: Go to File → Add Files to "[YourProject]"... and select the .xcframework.
  3. In the dialog that appears, make sure "Copy items if needed" is checked.
  4. Click Finish.

2. Embed the Framework

For the SDK to load properly at runtime, it must be embedded in your app's build phase.

  1. Select your app target in the Project Navigator.
  2. Go to the General tab.
  3. Scroll down to the "Frameworks, Libraries, and Embedded Content" section.
  4. If ZRTAttest.xcframework is not already listed, click the "+" button and add it.
  5. Set the Embed option to "Embed & Sign".

Phase 2: Generating the Token

3. SDK Invocation

Import the framework and invoke the ZRTAttestManager to generate a token.

API Reference:

PropertyDetail
MethodZRTAttestManager.generateToken(nonce: String) -> String
Parametersnonce (String) — A unique, one-time-use string provided by your backend server
Return ValueA signed JWT string (e.g., eyJhbGciOi...) on success, or an empty string "" on failure

Example (ViewController.swift):

import UIKit
import ZRTAttest

class ViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()

// 1. Fetch a fresh nonce from your backend server
let nonce = "server_generated_nonce_12345"

// 2. Generate the attestation token
let token = ZRTAttestManager.generateToken(nonce: nonce)

// 3. Validate generation success
if !token.isEmpty {
print("Successfully generated ZTRB Token: \(token)")
// Proceed to attach token to your outgoing API request
} else {
print("Token generation failed.")
}
}
}

4. Understanding the Cryptographic Nonce

When invoking generateToken(), you must pass a nonce (number used once). This string plays a critical role in the integrity of the Zero Root Trust process.

  • Prevention of Replay Attacks: The nonce ensures that every generated token is uniquely tied to a specific session or server request. Malicious actors cannot intercept a valid token and successfully reuse it later, because the outdated nonce bound to that token will be rejected by your backend.
  • Cryptographic Binding: When you pass the nonce into the SDK, it is securely embedded and signed into the generated ZTRB token's payload.

Possible Formats for Nonce:

FormatDescription
Server-Generated NonceA unique, cryptographically secure nonce fetched from your backend for every sensitive request or session.
Checksum of API Request PayloadA checksum generated from the API request body or critical transaction parameters.
Custom Validation StringAny custom string representing data important for integrity verification during testing or implementation.

Best Practices:

  • Dynamic & Unique: Must be generated dynamically by your backend server for each new sensitive action.
  • Unpredictable: Generated using a cryptographically secure random number generator (CSRNG).
  • Time-bound: The server should associate a strict expiration time with the nonce (e.g., 60 seconds).

Phase 3: Transmission & Endpoint Security

5. Transmitting the Token via HTTP Headers

To ensure your backend can seamlessly verify the integrity of the request, do not send the token in the request body or URL parameters. It must be attached as a standard HTTP Header on your outgoing network requests (e.g., via URLSession, Alamofire, or Moya).

We recommend using a dedicated custom header to avoid conflicts with standard OAuth/Session tokens:

  • Header Name: X-ZRT-Token
  • Header Value: <the_generated_zrt_token>

Example — URLSession:

func makeSecureAPIRequest(nonce: String) {
// Generate token dynamically right before the network call
let token = ZRTAttestManager.generateToken(nonce: nonce)

guard let url = URL(string: "https://api.yourdomain.com/v1/secure-endpoint") else { return }
var request = URLRequest(url: url)
request.httpMethod = "POST"

// Attach the ZTRB Token
request.setValue(token, forHTTPHeaderField: "X-ZRT-Token")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")

let task = URLSession.shared.dataTask(with: request) { data, response, error in
// Handle response
}
task.resume()
}

6. Securing Critical Business Logic

A Zero-Trust architecture assumes the client device is inherently compromised. To properly protect your business, you must enforce ZTRB token validation on as many high-risk endpoints as possible.

The Golden Rule

If a specific API endpoint modifies data, moves money, or grants access, it should require a fresh ZTRB token generated using a fresh, server-issued nonce.

Do not limit token validation to just the login screen. You should require a fresh nonce and a newly generated ZTRB token for all of the following critical pathways:

Authentication & Onboarding

  • Account creation and login endpoints
  • Password resets and MFA verification steps

Financial & Transactional Logic

  • Checkout processing, wallet top-ups, and fund transfers
  • Adding or modifying payment methods

Profile & PII Mutations

  • Updating email addresses, phone numbers, or physical addresses
  • Viewing or exporting sensitive PII data

Core App Economy

  • Claiming rewards, redeeming promo codes, or executing high-value in-app actions that are frequent targets for botting and automation.

Troubleshooting Reference

IssuePotential CauseSolution
Token is emptyDefender SDK not loaded at runtimeEnsure the Defender binary is properly injected into the app environment before token generation is called
Module 'ZRTAttest' not foundFramework not embedded correctlyVerify Phase 1, Step 2 — ensure "Embed & Sign" is explicitly selected in the target settings
Build error on simulatorMissing simulator slice in the binaryEnsure the .xcframework provided was built with the -dev flag for local simulator support

3. Backend Integration Guide

This guide outlines the steps required to integrate the Trust API Bind (TAB) validation module into your backend infrastructure. This module dynamically extracts the X.509 certificate chain from incoming JWTs, verifies the cryptographic signature against the Bugsmirror Root CA, and enforces strict temporal binding to prevent replay attacks and time manipulation.

Phase 1: Required Dependencies

To handle JWT parsing and X.509 certificate extraction securely, you must add the enterprise-standard libraries to your project based on programming language.


Phase 2: Core Validation Module Setup and Configuration Guide

Import and integrate the validation module in your project. Initialize the validator in the main file of your server with the following parameters.

Argument Definitions & Security Implications:

ArgumentTypeDescription
packageNameStringThe unique identifier for the target application.
expiryDurationSecondslongMaximum allowed age of a token (in seconds) before permanent rejection. Recommended: 30
allowedClockDriftSecondslongThe maximum time tolerance (in seconds) that allows a token's clock to be ahead of the server's clock. This value can be adjusted based on the client user base. Additionally, it is recommended to mitigate on client-side UI based on the response. Recommended: 5
rootCertFilePathStringFile path to the PEM-encoded public key/certificate.
serialIdFilePathStringPath to the JSON registry containing known revoked hardware identifiers.
Note

The ROOT_CA_PEM must be stored in a secure environment variable or Secret Manager.


Phase 3: Validation Process

The globally initialized validator can be passed into middleware or directly into APIs. On calling the validate() function from the initialised validator nonce and revocation of device being extracted and every incoming request gets secured and following claims get validated.

note

Enforce the status and error messages returned by the validate function into standard API responses.

Claims Definitions & Security Implications:

ClaimTypeDescriptionSecurity Implication
nonceStringA unique, one-time-use string embedded within the token to ensure request uniqueness.Prevents "Replay Attacks" where a legitimate request is intercepted and resent by an adversary.
pkgStringThe unique application identifier string used to validate whether the request is from the specified application.Request from genuine application is crucial. Mismatch of this string will cause the cryptographic signature check to fail instantly.
iatlongTime-based claims indicating when the token was created and when it becomes invalid.Strict Replay Protection. By keeping this window small (60 seconds), you drastically reduce the risk profile if an attacker successfully intercepts a token in transit.
v_stateStringA status claim indicating the security posture of the originating environment.This status indicator verifies the legitimacy of the request environment. Refer to the table below for a detailed breakdown of its possible values.
cert_serialsArrayThe unique hardware or certificate serial numbers associated with the device.Enables precise "Hardware Binding," ensuring the token is only valid when presented by the specific device to which it was issued.
v_2fa (in Preview (Beta) )StringContains a high-assurance cryptographic trust proof that enables backend services to independently verify the authenticity of the requesting application and device. This claim can be used as an additional trust factor for sensitive operations, including transaction authorization, fraud prevention, adaptive access control, account protection, and step-up verification workflows. By validating this claim, backend systems can make stronger risk-based decisions regarding the legitimacy of a request and its execution environment.Support will be available in 450+ CLI releases. Integration documentation and validation guidelines will be provided upon general availability.

Enforcement of v_state claim:

This v_state can be used to determine legitimacy of the environment in which the application is running as long as the underlying defender vm is intact.

V_STATE ValuesDescriptionRemark/Action
UnknownThe Defender cannot establish the device's current status. This typically arises from factors such as the device lacking essential secure hardware, the application operating on a version prior to Android 10, or the Defender still being in the process of evaluating the environment.For high-risk operations (such as financial transactions, account recovery, or sensitive data access), the request should be denied or challenged. For lower-risk operations, the application may retry attestation and re-evaluate the request.
FailedThe Defender has determined that the device does not meet the required integrity or trust criteria. This may indicate a compromised, tampered, emulated, or otherwise untrusted execution environment.The backend should deny the request and prevent access to protected functionality. Additional monitoring or fraud controls may be applied according to organizational policy.
PassedThe Defender has validated the device using standard integrity signals and determined that the device appears legitimate. This assessment is based on the integrity information available at the time of evaluation.Suitable for most commercial applications and standard business workflows where a balance between security, user experience, and device coverage is desired. The server may accept requests and apply standard risk controls.
TrustedThe Defender has validated the device using the strongest available integrity signals, providing a higher level of confidence in the device's authenticity and execution environment compared to the Passed level. This assessment depends on the integrity and security of the underlying attestation mechanisms and platform signals.Intended for applications requiring the highest level of device trust. Because Trusted relies on stronger integrity requirements, it may reduce the number of eligible devices compared to Passed. Use this level for high-risk operations, sensitive transactions, privileged actions, or environments where enhanced security is prioritized over maximum device coverage.

Appendix

Implementation in Java

Required Dependencies

Add the following to your pom.xml:

<dependencies>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.12.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.12.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.12.5</version>
<scope>runtime</scope>
</dependency>
<!-- X.509 Certificate Validation (REQUIRED) -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.70</version>
</dependency>
<!-- JSON Parsing for Revoked Certs (REQUIRED) -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
</dependencies>

Implementation Example

package example;

import org.bugsmirror.TokenValidator;

public class Main {
public static void main(String[] args) {
try {
TokenValidator validator = new TokenValidator(
"com.example.pkg", // package name of the application
300, // token expiration time
5, // clock drift duration
"./assets/rootCA.pem", // root certificate path
"./assets/serialId.json" // serial IDs JSON path
);

String tokenString = ""; // token from request header

TokenValidator.ValidationResult result = validator.validate(tokenString);

// Values like clock value, package name, nonce, etc.
// can be retrieved from the TAB response even in case of error
if (!result.error.error.isEmpty()) {
throw new Exception("Error occurred: " + result.error.error
+ " with status: " + result.error.errorStatus);
}

if (result.response != null) {
// Validate the revocation of the device from which the request is initiated
System.out.printf("Is Revoked: %s", result.response.isRevoked);
System.out.printf("Nonce: %s", result.response.nonce);
System.out.printf("PackageName: %s", result.response.packageName);
System.out.printf("Issued AT: %s", result.response.issuedAt);
System.out.printf("Clock Value: %s", result.response.clockValueInSeconds);
}

} catch (Exception e) {
System.out.printf("Exception occurred: %s", e.getMessage());
}
}
}

Error Specification

ConditionReturned ErrorStatusReturned Error Message
Validator config is missing/invalidMISSINGsystem configuration error: missing required configuration parameters
tokenString is emptyMISSINGsystem configuration error: missing required configuration parameters
Token is not RSA signedMALFORMEDtoken signature/chain validation failed: unexpected signing algorithm: [alg]
Missing/invalid x5c headerMALFORMEDtoken signature/chain validation failed: missing x5c certificate chain
x5c leaf fails root verificationMALFORMEDtoken signature/chain validation failed: UNAUTHORIZED: Untrusted leaf certificate chain
Missing iat claimSecurityAlertmissing 'iat' (Issued At) claim
iat is further in future than allowed driftSecurityAlerttoken claims to be from the future
Token age exceeds expiryDurationUNAUTHORIZEDtoken expired
Missing nonce claimSecurityAlertmissing 'nonce' claim
Missing v_state claimSecurityAlertmissing required v_state claim
Missing or mismatched pkg claimSecurityAlertmissing required pkg claim OR package name does not match
All checks passSUCCESS(empty string)

Implementation in Golang

Required Dependencies

Add the following to your go.mod:

require (
github.com/golang-jwt/jwt/v5 v5.3.1
)

Implementation Example

import (
"TABBackendModule/TokenValidator"
"log"
)

func main() {
validator, err := TokenValidator.InitValidator(
"com.example.pkg", // package name of the application
300, // token expiration time
5, // clock drift duration
"./assets/rootCA.pem", // root certificate path
"./assets/serialId.json", // serial IDs JSON path
)
if err != nil {
log.Println(err)
return
}

tokenString := "" // token from request header

tabResp, tabErr := validator.Validate(tokenString)
// Values like clock value, package name, nonce, etc.
// can be retrieved from the TAB response even in case of error
if tabErr != nil {
log.Printf("Status: %v", tabErr.ErrorStatus.String())
log.Printf("Error: %v", tabErr)
}
if tabResp != nil {
// Validate the revocation of the device from which the request is initiated
log.Printf("Is Revoked: %v", tabResp.IsRevoked)
log.Printf("Nonce: %v", tabResp.Nonce)
log.Printf("PackageName: %v", tabResp.PackageName)
log.Printf("Issued AT: %v", tabResp.IssuedAt)
log.Printf("Clock Value: %v", tabResp.ClockValueInSeconds)
}
}

Error Specification

ConditionReturned ErrorStatusReturned Error Message
Validator is nilMISSINGvalidator is nil
Validator config is missing/invalidMISSINGsystem configuration error: missing required configuration parameters
tokenString is emptyMISSINGsystem configuration error: missing required configuration parameters
rootCert fails PEM decodeINVALIDsystem configuration error: failed to decode Root CA PEM
rootCert fails X509 parseINVALIDsystem configuration error: invalid Root CA format
Token is not RSA signedMALFORMEDtoken signature/chain validation failed: unexpected signing algorithm: [alg]
Missing/invalid x5c headerMALFORMEDtoken signature/chain validation failed: missing x5c certificate chain
x5c leaf fails root verificationMALFORMEDtoken signature/chain validation failed: UNAUTHORIZED: Untrusted leaf certificate chain
Missing iat claimSecurityAlertmissing 'iat' (Issued At) claim
iat is further in future than allowed driftSecurityAlerttoken claims to be from the future
Token age exceeds expiryDurationUNAUTHORIZEDtoken expired
Missing nonce claimSecurityAlertmissing 'nonce' claim
Missing v_state claimSecurityAlertmissing required v_state claim
Missing or mismatched pkg claimSecurityAlertmissing required pkg claim OR package name does not match
All checks passSUCCESS(empty string)

Impelementation in NodeJS

Required Dependencies

Add the following to your package.json:

"dependencies": {
"jsonwebtoken": "^9.0.2"
}

Implementation Example

const { Validator } = require('./validator');

function main() {
try {
const validator = new Validator(
"com.example.pkg", // package name of the application
300, // token expiration time
5, // clock drift duration
"./assets/rootCA.pem", // root certificate retrieved from the portal and
store into server's in-memory
"./assets/serialId.json" // path to serial ids JSON file
);
const tokenString = ""; // token is stored in request header
const result = validator.validate(tokenString);
// the values like clock value, package name, nonce, etc.
// can be retrieved from tab response even in case of error
if (result.tabError.error !== "") {
throw new Error(`Error occurred: ${result.tabError.error} with status:
${result.tabError.errorStatus}`);
}
if (result.tabResponse) {
// validate the revocation of the device from which the request is being
initiated
console.log(`Is Revoked: ${result.tabResponse.isRevoked}`);
// values extracted from claims
console.log(`Nonce: ${result.tabResponse.nonce}`);
console.log(`PackageName: ${result.tabResponse.packageName}`);
console.log(`Issued AT: ${result.tabResponse.issuedAt}`);
// duration in seconds calculated using issued at time
console.log(`Clock Value: ${result.tabResponse.clockValueInSeconds}`);
}
} catch (e) {
console.log(`Exception occurred: ${e.message}`);
}
}

main();

Error Sepcification

ConditionReturned ErrorStatusReturned Error (Message)
Validator config is missing/invalidMISSING"system configuration error: missing required configuration parameters"
tokenString is emptyMISSING"system configuration error: missing required configuration parameters" (Note: This reflects the exact code provided)
Token is not RSA signedMALFORMED"token signature/chain validation failed: unexpected signing algorithm: [alg]"
Missing/invalid x5c headerMALFORMED"token signature/chain validation failed: missing x5c certificate chain"
x5c leaf fails root verificationMALFORMED"token signature/chain validation failed: UNAUTHORIZED: Untrusted leaf certificate chain"
Missing iat claimSecurityAlert"missing 'iat' (Issued At) claim"
iat is further in future than allowed driftSecurityAlert"token claims to be from the future"
Token age exceeds expiryDurationUNAUTHORIZED"token expired"
Missing nonce claimSecurityAlert"missing 'nonce' claim"
Missing v_state claimSecurityAlert"missing required v_state claim"
Missing or mismatched pkg claimSecurityAlert"missing required pkg claim" OR "package name does not match"
All checks passSUCCESS(Empty String)