API Authentication

Authentication steps are described here in detail.

VaultN API requires a robust and secure authentication mechanism to ensure trusted access, prevent unauthorized API requests, and safeguard digital transactions. This guide provides a step-by-step process for certificate-based authentication, API token generation, and implementation across multiple programming environments including C#, PHP, Java, Node.js, and Python.

Generating and Uploading a Certificate

To authenticate against VaultN API, users must first generate and upload a .crt certificate that serves as the identity verification key.

Creating a Certificate Using OpenSSL

Execute the following commands in the OpenSSL command prompt:

openssl req -new -newkey rsa:2048 -passout pass:password -nodes -out sample.csr -keyout sample.key
openssl x509 -req -days 365 -in sample.csr -signkey sample.key -out sample.crt
openssl pkcs12 -export -in sample.crt -inkey sample.key -out sample.pfx

Explanation of Commands

  • The first command generates a certificate signing request (.csr) and a private key (.key).
  • The second command signs the request, generating a public certificate (.crt).
  • The third command creates a PKCS#12 archive (.pfx file) for secure API authentication.

Uploading the Certificate to VaultN
1. Log in to VaultN Dashboard.
2. Navigate to Settings → Certificates → Add Certificate.
3. Upload the .crt file.
4. Once uploaded, the certificate will be used for API authentication.

Important Notes:
• The -days parameter determines the validity period of the certificate. Adjust as required.
• The .crt filename must be unique when re-uploading to VaultN. Duplicate filenames may cause upload failures without a prompt.
• For Windows users, run OpenSSL with administrative privileges.

VaultN supports X.509 certificate-based authentication, ensuring that API clients authenticate via a secure digital certificate (.pfx) before accessing API endpoints. The authentication process consists of the following steps:
1. Generating and uploading a certificate to the VaultN platform.
2. Using the uploaded certificate to generate a JWT (JSON Web Token) for authentication.
3. Passing the JWT token as a Bearer token in API requests.

The following code snippets in (currently available for C#, PHP, Java & Node.js) demonstrates how to acquire the token string.

public string GenerateToken(string vaultGuid) 
{ 
  var tokenHandler = new JwtSecurityTokenHandler(); 
  var cert = new X509Certificate2("{pfxFilePath}", "{pfxPassword}"); 
	var cred = new X509SigningCredentials(cert); 
 
	var tokenDescriptor = new SecurityTokenDescriptor { 
    Issuer = "Self", 
    Audience = "VAULTN", 
    Subject = new ClaimsIdentity(new Claim[] { 
      new Claim(JwtRegisteredClaimNames.Sub, userGuid)  }), 
    Expires = DateTime.UtcNow.AddDays(365), 
    SigningCredentials = cred 
 	};
  
 	var token = tokenHandler.CreateToken(tokenDescriptor); 
	var retval = tokenHandler.WriteToken(token);
  
  return retval;
}
<?php

require __DIR__ . "/vendor/autoload.php";
use Firebase\JWT\JWT;

// Load private key, certificate, and CA certificates from PFX file
$pfxFile = "sample.pfx";
$password = "password";
$certs = [];

if (openssl_pkcs12_read(file_get_contents($pfxFile), $certs, $password)) {
    // PFX file loaded successfully
    $privateKey = $certs["pkey"];
    $certificate = $certs["cert"];
} else {
    // Failed to load PFX file
    echo "Failed to load PFX file.";
}

// Create hash value from certificate
$certificateHash = openssl_x509_fingerprint($certificate, "sha1", true);

// Convert hash value into base64url
$base64urlHash = base64_encode($certificateHash);
$x5t = str_replace(["+", "/", "="], ["", "", ""], $base64urlHash);
$kid = strtoupper(openssl_x509_fingerprint($certificate, "sha1", false));

// Use the $base64urlHash as needed
$header = [
    "typ" => "JWT",
    "alg" => "RS256", // Ensure this matches your signing algorithm
    "x5t" => $x5t,
];

// Define your payload
$payload = [
    "iss" => "Self",
    "aud" => "identity.vaultn.com",
    "sub" => "", // your VaultGuid here
    "iat" => time(),
    "exp" => time() + (60 * 60 * 24 * 365), // Token expiration time (1 year)
];

// Generate the JWT token
$jwt = JWT::encode($payload, $privateKey, "RS256", $kid, $header);

echo $jwt;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Date;
import java.util.Enumeration;

import org.apache.commons.codec.binary.Base64;
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JOSEObjectType;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.JWSSigner;
import com.nimbusds.jose.crypto.RSASSASigner;
import com.nimbusds.jose.util.Base64URL;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;

private String getAuthToken() throws IOException {
   try {
      char[] password = crtPass.toCharArray();

      KeyStore keyStore = KeyStore.getInstance("PKCS12");
      try (FileInputStream fileInputStream = new FileInputStream(crtPath)) {
         keyStore.load(fileInputStream, password);
      }

      PrivateKey privateKey = null;
      Certificate certificate = null;

      Enumeration<String> aliases = keyStore.aliases();
      while (aliases.hasMoreElements()) {
         String alias = aliases.nextElement();
         if (keyStore.isKeyEntry(alias)) {
            privateKey = (PrivateKey) keyStore.getKey(alias, password);
            certificate = keyStore.getCertificate(alias);
            break;
         }
      }

      MessageDigest sha1Digest = MessageDigest.getInstance("SHA-1");

      if (certificate == null) {
         throw new IOException("Error while reading the certificate. Certificate cannot be null.");
      }

      byte[] certificateHash = sha1Digest.digest(certificate.getEncoded());

      String base64urlHash = Base64.encodeBase64URLSafeString(certificateHash);
      String x5t = base64urlHash.replace("=", "");

      String kid = getHexEncodedFingerprint((X509Certificate) certificate);

      JWSHeader jwsHeader = new JWSHeader.Builder(JWSAlgorithm.RS256)
            .type(JOSEObjectType.JWT)
            .x509CertThumbprint(new Base64URL(x5t))
            .keyID(kid)
            .build();

      JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
            .issuer(crtIssuer)
            .audience(crtAudience)
            .subject(userUid)
            .issueTime(new Date())
            .expirationTime(new Date(System.currentTimeMillis() + (60L * 60 * 24 * 365 * 1000))) // Token expiration time (1 year)
            .build();

      JWSSigner signer = new RSASSASigner(privateKey);
      SignedJWT signedJWT = new SignedJWT(jwsHeader, claimsSet);
      signedJWT.sign(signer);

      String jwt = signedJWT.serialize();
      return jwt;
   } catch (JOSEException | NoSuchAlgorithmException | UnrecoverableKeyException | CertificateException | KeyStoreException e) {
      throw new IOException(e.getMessage());
   }
}

private static String getHexEncodedFingerprint(X509Certificate cert) throws IOException {
   try {
      MessageDigest md = MessageDigest.getInstance("SHA-1");
      byte[] digest = md.digest(cert.getEncoded());
      return bytesToHex(digest);
   } catch (Exception e) {
      throw new IOException(e.getMessage());
   }
}

private static String bytesToHex(byte[] bytes) {
   StringBuilder sb = new StringBuilder();
   for (byte b : bytes) {
      sb.append(String.format("%02X", b));
   }
   return sb.toString();
}
const forge = require('node-forge');
const fs = require('fs');
const jwt = require('jsonwebtoken');
 
// Load PFX file
const pfxPath = './sample.pfx';
const pfxPassword = 'password';
const pfxData = fs.readFileSync(pfxPath, 'binary');
 
// Parse PFX file
const pfxAsn1 = forge.asn1.fromDer(pfxData, false);
const pfx = forge.pkcs12.pkcs12FromAsn1(pfxAsn1, false, pfxPassword);
 
// Extract private key and certificate
let privateKey, certificate;
for (const safeContent of pfx.safeContents) {
  for (const safeBag of safeContent.safeBags) {
    if (safeBag.type === forge.pki.oids.certBag) {
      // Extract certificate
      certificate = forge.pki.certificateToPem(safeBag.cert);
    } else if (safeBag.type === forge.pki.oids.keyBag || safeBag.type === forge.pki.oids.pkcs8ShroudedKeyBag) {
      // Extract private key
      privateKey = forge.pki.privateKeyToPem(safeBag.key);
    }
  }
}
 
const certDer = forge.asn1.toDer(forge.pki.certificateToAsn1(forge.pki.certificateFromPem(certificate))).getBytes();
const x5t = forge.util.encode64(forge.md.sha1.create().update(certDer).digest().bytes());
const kid = forge.md.sha1.create().update(certDer).digest().toHex();
 
const payload = {
    sub: userGuid,
    iat: Math.floor(Date.now() / 1000) - 30,
    exp: Math.floor(Date.now() / 1000) + 60 * 60,
    iss: "",
    aud: ""
 
  };
  
  const signOptions = {
    algorithm: "RS256",    
    header: {
      x5t: x5t.replace(/=/g, ''),
      kid: kid.toUpperCase()
    }
  };
  
  // Sign JWT
  const token = jwt.sign(payload, privateKey, signOptions);
  
  console.log("JWT Token:", token);
# pip3 install cryptography pyjwt

import base64
from cryptography.hazmat.primitives.serialization import Encoding
from cryptography.hazmat.primitives.serialization.pkcs12 import load_key_and_certificates
import hashlib
import jwt
import time

pfx_path = './sample.pfx'
with open(pfx_path, 'rb') as f:
  pfx_contents = f.read()
pfx_password = 'a-password'
private_key, main_cert, _ = load_key_and_certificates(pfx_contents, pfx_password.encode())

# get certificate fingerprints (x5t, kid)
cert_der = main_cert.public_bytes(encoding=Encoding.DER)
cert_sha1 = hashlib.sha1(cert_der)
x5t = base64.b64encode(cert_sha1.digest()).decode().rstrip('=')
kid = cert_sha1.hexdigest().upper()

# create jwt payload
user_guid = 'your-user-guid-here'
now = int(time.time())
payload = {
  "sub": user_guid,
  "iat": now - 30,
  "exp": now + (60 * 60),  # 1 hour
  "iss": "Self",
  "aud": "vaultn.com",
}

jwt_token = jwt.encode(
  payload,
  private_key,
  headers={
    'alg':'RS256',
    'typ': 'JWT',
    'kid': kid,
    'x5t': x5t,
  },
)

  • Replace the .pfx file path and password accordingly.
  • While defining the Claim, use your VaultN Guid as the parameter vaultGuid _found under _VaultN -> Settings.
  • It is to be used as a Bearer token.

Best Practices

Store API keys securely; never hardcode them in public repositories.

Rotate certificates periodically to maintain security compliance.

Use OAuth token expiration mechanisms to prevent unauthorized access.

Log authentication attempts and API activity for auditing.


Additional Notes

For C#

  • Ensure System.IdentityModel.Tokens.Jwt is included as a project reference.
  • The AddDays() method determines the token’s expiration period, which should not exceed the certificate’s validity.

For PHP

  • Install the required package using composer require firebase/php-jwt.
  • The implementation is compatible with PHP 5.6 and later versions.
  • The expiration ("exp" => time() + (60 60 24 * 365)) defines the token validity in seconds (1 year) and can be adjusted as needed.

For any questions or to report issues, please contact [email protected].