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.
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')
}
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:
| Format | Description |
|---|---|
| Server-Generated Nonce | A unique, cryptographically secure nonce fetched from your backend for every sensitive request or session. |
| Checksum of API Request Payload | A checksum generated from the API request body or critical transaction parameters. |
| Custom Validation String | Any 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.
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
| Requirement | Version |
|---|---|
| Xcode | 14.0 or later |
| iOS Deployment Target | 13.0+ |
| Framework | ZRTAttest.xcframework (provided by Bugsmirror) |
1. Add the XCFramework to Your Project
- Open your Xcode project.
- Drag
ZRTAttest.xcframeworkinto the Project Navigator panel (left sidebar).- Alternatively: Go to File → Add Files to "[YourProject]"... and select the
.xcframework.
- Alternatively: Go to File → Add Files to "[YourProject]"... and select the
- In the dialog that appears, make sure "Copy items if needed" is checked.
- Click Finish.
2. Embed the Framework
For the SDK to load properly at runtime, it must be embedded in your app's build phase.
- Select your app target in the Project Navigator.
- Go to the General tab.
- Scroll down to the "Frameworks, Libraries, and Embedded Content" section.
- If
ZRTAttest.xcframeworkis not already listed, click the "+" button and add it. - 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:
| Property | Detail |
|---|---|
| Method | ZRTAttestManager.generateToken(nonce: String) -> String |
| Parameters | nonce (String) — A unique, one-time-use string provided by your backend server |
| Return Value | A 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:
| Format | Description |
|---|---|
| Server-Generated Nonce | A unique, cryptographically secure nonce fetched from your backend for every sensitive request or session. |
| Checksum of API Request Payload | A checksum generated from the API request body or critical transaction parameters. |
| Custom Validation String | Any 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.
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
| Issue | Potential Cause | Solution |
|---|---|---|
| Token is empty | Defender SDK not loaded at runtime | Ensure the Defender binary is properly injected into the app environment before token generation is called |
| Module 'ZRTAttest' not found | Framework not embedded correctly | Verify Phase 1, Step 2 — ensure "Embed & Sign" is explicitly selected in the target settings |
| Build error on simulator | Missing simulator slice in the binary | Ensure 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:
| Argument | Type | Description |
|---|---|---|
packageName | String | The unique identifier for the target application. |
expiryDurationSeconds | long | Maximum allowed age of a token (in seconds) before permanent rejection. Recommended: 30 |
allowedClockDriftSeconds | long | The 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 |
rootCertFilePath | String | File path to the PEM-encoded public key/certificate. |
serialIdFilePath | String | Path to the JSON registry containing known revoked hardware identifiers. |
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.
Enforce the status and error messages returned by the validate function into standard API responses.
Claims Definitions & Security Implications:
| Claim | Type | Description | Security Implication |
|---|---|---|---|
nonce | String | A 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. |
pkg | String | The 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. |
iat | long | Time-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_state | String | A 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_serials | Array | The 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) ) | String | Contains 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 Values | Description | Remark/Action |
|---|---|---|
| Unknown | The 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. |
| Failed | The 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. |
| Passed | The 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. |
| Trusted | The 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
| Condition | Returned ErrorStatus | Returned Error Message |
|---|---|---|
| Validator config is missing/invalid | MISSING | system configuration error: missing required configuration parameters |
tokenString is empty | MISSING | system configuration error: missing required configuration parameters |
| Token is not RSA signed | MALFORMED | token signature/chain validation failed: unexpected signing algorithm: [alg] |
| Missing/invalid x5c header | MALFORMED | token signature/chain validation failed: missing x5c certificate chain |
| x5c leaf fails root verification | MALFORMED | token signature/chain validation failed: UNAUTHORIZED: Untrusted leaf certificate chain |
Missing iat claim | SecurityAlert | missing 'iat' (Issued At) claim |
iat is further in future than allowed drift | SecurityAlert | token claims to be from the future |
Token age exceeds expiryDuration | UNAUTHORIZED | token expired |
Missing nonce claim | SecurityAlert | missing 'nonce' claim |
Missing v_state claim | SecurityAlert | missing required v_state claim |
Missing or mismatched pkg claim | SecurityAlert | missing required pkg claim OR package name does not match |
| All checks pass | SUCCESS | (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
| Condition | Returned ErrorStatus | Returned Error Message |
|---|---|---|
| Validator is nil | MISSING | validator is nil |
| Validator config is missing/invalid | MISSING | system configuration error: missing required configuration parameters |
tokenString is empty | MISSING | system configuration error: missing required configuration parameters |
rootCert fails PEM decode | INVALID | system configuration error: failed to decode Root CA PEM |
rootCert fails X509 parse | INVALID | system configuration error: invalid Root CA format |
| Token is not RSA signed | MALFORMED | token signature/chain validation failed: unexpected signing algorithm: [alg] |
| Missing/invalid x5c header | MALFORMED | token signature/chain validation failed: missing x5c certificate chain |
| x5c leaf fails root verification | MALFORMED | token signature/chain validation failed: UNAUTHORIZED: Untrusted leaf certificate chain |
Missing iat claim | SecurityAlert | missing 'iat' (Issued At) claim |
iat is further in future than allowed drift | SecurityAlert | token claims to be from the future |
Token age exceeds expiryDuration | UNAUTHORIZED | token expired |
Missing nonce claim | SecurityAlert | missing 'nonce' claim |
Missing v_state claim | SecurityAlert | missing required v_state claim |
Missing or mismatched pkg claim | SecurityAlert | missing required pkg claim OR package name does not match |
| All checks pass | SUCCESS | (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
| Condition | Returned ErrorStatus | Returned Error (Message) |
|---|---|---|
Validator config is missing/invalid | MISSING | "system configuration error: missing required configuration parameters" |
tokenString is empty | MISSING | "system configuration error: missing required configuration parameters" (Note: This reflects the exact code provided) |
| Token is not RSA signed | MALFORMED | "token signature/chain validation failed: unexpected signing algorithm: [alg]" |
| Missing/invalid x5c header | MALFORMED | "token signature/chain validation failed: missing x5c certificate chain" |
x5c leaf fails root verification | MALFORMED | "token signature/chain validation failed: UNAUTHORIZED: Untrusted leaf certificate chain" |
| Missing iat claim | SecurityAlert | "missing 'iat' (Issued At) claim" |
| iat is further in future than allowed drift | SecurityAlert | "token claims to be from the future" |
Token age exceeds expiryDuration | UNAUTHORIZED | "token expired" |
Missing nonce claim | SecurityAlert | "missing 'nonce' claim" |
Missing v_state claim | SecurityAlert | "missing required v_state claim" |
Missing or mismatched pkg claim | SecurityAlert | "missing required pkg claim" OR "package name does not match" |
| All checks pass | SUCCESS | (Empty String) |