Skip to main content

JWT Setup

Prerequisites

Before you begin, ensure you have the following:

Common Requirements

  • Access to the TrueCredential API base URL
  • A registered Subscription ID (obtained from your TrueCredential Marketplace)

Language-Specific Requirements

  • .NET 8.0 or higher
  • Visual Studio, Visual Studio Code, or any C#-compatible IDE

Generate RSA Key Pair

You can generate RSA keys using any of the following methods. Each method creates:

  • A private key file (private_key.pem) - Keep this secure and never share it.
  • A public key file (public_key.pem) - Update your SaaS Accelerator configuration with this for token validation.
  • Console output displays both keys in Base64 format (without PEM headers), making them easy to copy and use directly.

Implementation

This method uses C#'s built-in System.Security.Cryptography library to generate cryptographically secure RSA keys.

using System.Security.Cryptography;
using System.Text;

class GenerateRsaKeys
{
static void Main(string[] args)
{
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine("Generating TrueCredential-compatible RSA key pair...");

int keySize = 2048;
string outputPath = Path.Combine(AppContext.BaseDirectory, "output");
Directory.CreateDirectory(outputPath);

using (var rsa = RSA.Create(keySize))
{
// Export private key (PKCS#8)
var privateKeyBytes = rsa.ExportPkcs8PrivateKey();
string privateKeyBase64 = Convert.ToBase64String(privateKeyBytes);
string privateKeyPem = "-----BEGIN PRIVATE KEY-----\n" +
privateKeyBase64 +
"\n-----END PRIVATE KEY-----";

// Export public key (SPKI)
var publicKeyBytes = rsa.ExportSubjectPublicKeyInfo();
string publicKeyBase64 = Convert.ToBase64String(publicKeyBytes);
string publicKeyPem = "-----BEGIN PUBLIC KEY-----\n" +
publicKeyBase64 +
"\n-----END PUBLIC KEY-----";

// Save full PEMs to files
string privateKeyPath = Path.Combine(outputPath, "private_key.pem");
string publicKeyPath = Path.Combine(outputPath, "public_key.pem");

File.WriteAllText(privateKeyPath, privateKeyPem, Encoding.ASCII);
File.WriteAllText(publicKeyPath, publicKeyPem, Encoding.ASCII);

// Show only Base64 in console (without BEGIN/END)
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("\n========================================");
Console.WriteLine("TrueCredential-compatible keys generated successfully!");
Console.WriteLine("========================================");

Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine($"Private Key saved to: {privateKeyPath}");
Console.WriteLine($"Public Key saved to: {publicKeyPath}");

Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("\n--- PUBLIC KEY (Base64 only) ---");
Console.WriteLine(publicKeyBase64);

Console.WriteLine("\n--- PRIVATE KEY (Base64 only) ---");
Console.WriteLine(privateKeyBase64);
}
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine("\nPress any key to exit...");
Console.ReadKey();
}
}

Output Summary

After running the code in your preferred language, the following files will be created:

File NameDescriptionFormat
private_key.pemYour private RSA key — used to sign JWT tokens for TrueCredential authentication. Keep this file secure and never share it.PKCS#8
public_key.pemYour public RSA key — use this to update your SaaS Accelerator configuration for token validation.SPKI

Console Output: Displays both the public and private keys in Base64 format (without PEM headers) for easy reference or embedding.

Key Generation Summary
  • All methods generate RSA key pairs using 2048-bit encryption
  • Keys are stored in PEM format
  • Console output provides Base64 versions (without PEM headers)

Generate JWT Token & Invoke Workflow

After generating your RSA key pair and obtaining your Subscription ID, use your private key to sign JWT tokens that authenticate TrueCredential workflow API call.

Process Overview

  1. Load the private key generated earlier (private_key.pem)
  2. Generate a JWT token containing the required claims, signed with your private key
  3. Invoke the workflow API using the token for authenticated access

JWT Token Parameters

ParameterValueDescription
audTrueCredential.APIAudience for which the token is intended
issTrueCredential.TokenIssuerToken issuer identifier
exp+180 secondsToken expiration (3 minutes from creation)
kidsamplekeyKey identifier used for signature verification
redirectUrlYour redirect URLClient redirect URL
clientYour Subscription IDIdentifier obtained from your TrueCredential Marketplace

Implementation

Install Required NuGet Package

  • System.IdentityModel.Tokens.Jwt
using System.Security.Cryptography;
using Microsoft.IdentityModel.JsonWebTokens;
using System.Text.RegularExpressions;
using Microsoft.IdentityModel.Tokens;

class JwtWorkflowBuilder
{
static void Main(string[] args)
{
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine("TrueCredential JWT Workflow Builder");
Console.WriteLine("========================================\n");

// CONFIGURE THESE VALUES
string privateKeyPath = Path.Combine(AppContext.BaseDirectory, "output", "private_key.pem");
string clientId = "YOUR_SUBSCRIPTION_ID_HERE";
string redirectUrl = "https://your-redirect-url.com";
string baseUrl = "https://www.true-credential.com";
string workflowId = "IssueCredential";

try
{
// Read private key from file
if (!File.Exists(privateKeyPath))
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"Error: Private key not found at: {privateKeyPath}");
Console.WriteLine("Please ensure you've run Step 1 (Generate RSA Keys) first.");
Console.ResetColor();
return;
}

string privateKeyPem = File.ReadAllText(privateKeyPath);

// Parse PEM and create RSA key
using (RSA rsa = RSA.Create())
{
int bytesRead;
rsa.ImportPkcs8PrivateKey(ReadKeyString(privateKeyPem), out bytesRead);
var rsaSecurityKey = new RsaSecurityKey(rsa);
rsaSecurityKey.KeyId = "samplekey";

// Create JWT token
var tokenHandler = new JsonWebTokenHandler();
var now = DateTime.UtcNow;

var tokenDescriptor = new SecurityTokenDescriptor
{
Audience = "TrueCredential.API",
Issuer = "TrueCredential.TokenIssuer",
IssuedAt = now,
NotBefore = now,
Expires = now.AddSeconds(180),
SigningCredentials = new SigningCredentials(rsaSecurityKey, SecurityAlgorithms.RsaSha256),
Claims = new Dictionary<string, object>
{
{ "redirectUrl", redirectUrl },
{ "client", clientId }
}
};

// Add custom header (kid)
tokenHandler.SetDefaultTimesOnTokenCreation = false;
var token = tokenHandler.CreateToken(tokenDescriptor);

// Display results
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("JWT Token Generated Successfully!");
Console.WriteLine("========================================\n");

Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("--- GENERATED JWT TOKEN ---");
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine(token);

Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine("\n--- WORKFLOW URL ---");
Console.ForegroundColor = ConsoleColor.White;
string workflowUrl = $"{baseUrl}/api/wf/connect?token={token}&workflow={workflowId}";
Console.WriteLine(workflowUrl);

Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine("\n--- CURL COMMAND ---");
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine($"curl -X GET \"{workflowUrl}\"");

Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine("\n========================================");
Console.WriteLine("Token expires in 3 minutes (180 seconds)");
Console.WriteLine("Run this program again to generate a new token");
Console.WriteLine("========================================");
}
}
catch (Exception ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"Error: {ex.Message}");
}
finally
{
Console.ResetColor();
Console.WriteLine("\nPress any key to exit...");
Console.ReadKey();
}

}
public static byte[] ReadKeyString(string pemOrBase64)
{
string privateKeyHeader = "-----BEGIN PRIVATE KEY-----";
string privateKeyFooter = "-----END PRIVATE KEY-----";
string publicKeyHeader = "-----BEGIN PUBLIC KEY-----";
string publicKeyFooter = "-----END PUBLIC KEY-----";

if (pemOrBase64.Contains(privateKeyHeader) && pemOrBase64.Contains(privateKeyFooter))
{
pemOrBase64 = pemOrBase64.Replace(privateKeyHeader, "")
.Replace(privateKeyFooter, "");
}
if (pemOrBase64.Contains(publicKeyHeader) && pemOrBase64.Contains(publicKeyFooter))
{
pemOrBase64 = pemOrBase64.Replace(publicKeyHeader, "")
.Replace(publicKeyFooter, "");
}

// Remove newlines and spaces properly
string base64 = Regex.Replace(pemOrBase64, @"\s+", "");
return Convert.FromBase64String(base64);
}
}

Configure Your Values:

string clientId = "YOUR_SUBSCRIPTION_ID_HERE";  // Replace with your actual Subscription ID
string redirectUrl = "https://your-redirect-url.com"; // Replace with client_url
string baseUrl = "https://www.true-credential.com"; // Replace with TrueCredential api base url
string workflowId = "id-proofing-vc-issuance"; // For ISSUANCE, use "vc-presentation" for PRESENTATION

Output Summary

After running the code, the console displays:

OutputDescription
JWT TokenSigned with your private key for TrueCredential authentication.
Workflow URLComplete API URL with the token and workflow ID.
cURL CommandCommand to call and test the workflow API endpoint from a terminal.

Using the Generated Workflow URL

You can now:

  1. Open the workflow URL directly in your browser, or
  2. Run the cURL command in your terminal to test the API call.
Token Expiration
  • JWT tokens are short-lived (180 seconds) for security.
  • Re-run the generation script or program to obtain a new token whenever needed.