Skip to main content
Version: 1.0

1.2 Verification Result

Verification Result

After a successful verification, VerifySpeed provides an encrypted token that contains the verification details. This token must be decrypted on your server using your server key to extract the verified phone number and other information.

Token Structure

The verification token contains four pieces of information separated by the | character:

phoneNumber|dateOfVerified|usedMethodName|verificationKey

Components:

  • phoneNumber: The verified phone number
  • dateOfVerified: The date and time when verification was completed
  • usedMethodName: The verification method that was used (e.g., "WhatsApp Message", "Telegram OTP", "SMS OTP")
  • verificationKey: A unique key for the verification instance used for server-side validation

Token Encryption

VerifySpeed encrypts the token using AES-256 encryption with the following process:

  1. Payload Creation: Combines the four components with | separator
  2. Key Derivation: Uses SHA256 hash of your server key as the AES key
  3. Encryption: Applies AES-256 encryption with a random IV
  4. Encoding: Returns the result as a Base64-encoded string

Verifying the Token

You must verify and decrypt the token on your server using your server key to access the verification details. We provide official packages for each programming language that contain the verification tools:

Important: The verify function throws an error if the token is older than 5 minutes.

Package Installation:

dotnet add package VerifySpeed.VSCSharp --version 1.0.15

Usage:

using VerifySpeed.VSCSharp;

// Verify and decrypt the verification token
var result = token.VerifyVerificationToken(serverKey);
Console.WriteLine($"Phone: {result.PhoneNumber}");
Console.WriteLine($"Verification Key: {result.VerificationKey}");

Manual Implementation

If you prefer to implement the verification manually or need to customize the behavior, here are the complete code examples:

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

public static class EncryptionTool
{
/// <summary>
/// Verifies and decrypts an encrypted verification token using the specified server key
/// and returns the corresponding VerificationResult object.
/// </summary>
/// <param name="token">The Base64-encoded encrypted token string to verify and decrypt.</param>
/// <param name="serverKey">The server key used for AES decryption.</param>
/// <returns>A VerificationResult object representing the decrypted token.</returns>
public static VerificationResult VerifyVerificationToken(this string token, string serverKey)
{
if (string.IsNullOrWhiteSpace(token))
{
throw new ArgumentException("The verification token cannot be null or empty");
}

string decrypted = Decrypt(token, serverKey);
string[] parts = decrypted.Split('|');

if (parts.Length < 4)
{
throw new ArgumentException("The token format is invalid or corrupted");
}

string phoneNumber = parts[0];
DateTime dateOfVerification = DateTime.Parse(parts[1]);
string methodName = parts[2];
string verificationKey = parts[3];

// Reject tokens older than 5 minutes
if (dateOfVerification.AddMinutes(5) < DateTime.UtcNow)
{
throw new ArgumentException("The verification token has expired");
}

return new VerificationResult
{
PhoneNumber = phoneNumber,
DateOfVerification = dateOfVerification,
MethodName = methodName,
VerificationKey = verificationKey
};
}

private static string Decrypt(string token, string serverKey)
{
try
{
byte[] cipherBytes = Convert.FromBase64String(token);
using var aes = Aes.Create();
aes.Key = SHA256.HashData(Encoding.UTF8.GetBytes(serverKey));

using var memoryStream = new MemoryStream(cipherBytes);
var iv = new byte[aes.BlockSize / 8];
_ = memoryStream.Read(iv);
aes.IV = iv;

using var cryptoStream = new CryptoStream(
memoryStream,
aes.CreateDecryptor(),
CryptoStreamMode.Read
);
using var streamReader = new StreamReader(cryptoStream);
return streamReader.ReadToEnd();
}
catch (Exception ex)
{
throw new Exception("Failed to decrypt the verification token", ex);
}
}
}

public class VerificationResult
{
public string PhoneNumber { get; set; }
public DateTime DateOfVerification { get; set; }
public string MethodName { get; set; }
public string VerificationKey { get; set; }
}

Security Considerations

  • Server Key Protection: Keep your server key secure and never expose it in client-side code
  • Token Validation: Always validate the decrypted data before using it in your application
  • Error Handling: Implement proper error handling for decryption failures
  • Token Expiry: Consider implementing token expiry validation based on the verification date

Integration Flow

  1. Client Side: User completes verification and receives encrypted token
  2. Client to Server: Send encrypted token to your backend
  3. Server Verification: Verify and decrypt token using your server key (reject if older than 5 minutes)
  4. Data Extraction: Extract phone number and verification details
  5. Application Logic: Use the verified phone number in your application

Error Handling

Common errors you may encounter:

  • Invalid Token Format: Token is corrupted or malformed
  • Decryption Failure: Server key mismatch or token corruption
  • Missing Data: Required token components are missing
  • Invalid Date: Verification date cannot be parsed
  • Token Expired: The verify function throws when the token is older than 5 minutes

Always implement proper error handling to gracefully manage these scenarios in your application.

Token Expiry Validation

Default Security: All official packages automatically validate that verification tokens are no older than 5 minutes. If a token is older than 5 minutes, the packages will throw an exception, preventing replay attacks and ensuring the verification is recent and valid.

Additional Security: If you need stricter security requirements (e.g., only accepting tokens that are no more than 2 minutes old), you can implement additional validation by checking the dateOfVerification field after decryption.

Here's an example of how to implement custom token expiry validation:

// First, verify the token using the official package (validates 5-minute expiry)
var result = token.VerifyVerificationToken(serverKey);

// Additional security: Check if token is no more than 2 minutes old
var tokenAge = DateTime.UtcNow - result.DateOfVerification;
if (tokenAge.TotalMinutes > 2)
{
throw new ArgumentException($"Token is too old for this operation. Age: {tokenAge.TotalMinutes:F1} minutes, Maximum allowed: 2 minutes");
}

// Token is valid and meets additional security requirements
Console.WriteLine($"Phone: {result.PhoneNumber}");
Console.WriteLine($"Verification Key: {result.VerificationKey}");