Build secure, verifiable, and blockchain-based digital identity solutions with our comprehensive Digital ID API. From personal verification to enterprise identity management, from QR-code sharing to secure contact exchange.
allgram Digital ID provides enterprise-level security, GDPR compliance, and seamless integration with popular platforms. Perfect for businesses, developers, and organizations requiring professional identity verification solutions.
AES-256, P2P, GDPR compliant
Instant contact sharing, encrypted data
REST API, SDKs, comprehensive docs
Build robust Digital ID applications with Node.js and Express.js. Our comprehensive API provides identity verification, QR code generation, and enterprise-grade security features. Perfect for building scalable backend services and Digital ID management systems.
// allgram Digital ID Node.js Integration Example
const express = require('express');
const crypto = require('crypto');
const axios = require('axios');
const QRCode = require('qrcode');
class allgramDigitalIDClient {
constructor(apiKey, baseUrl = 'https://api.allgram.best') {
this.apiKey = apiKey;
this.baseUrl = baseUrl;
this.digitalIDs = new Map();
}
// Create Digital ID verification request
async createDigitalIDRequest(userData) {
try {
const response = await axios.post(`${this.baseUrl}/account/v1/did/create/`, {
first_name: userData.firstName,
last_name: userData.lastName,
third_name: userData.thirdName,
gender: userData.gender,
place_of_birth: userData.placeOfBirth,
nationality: userData.nationality,
date_of_birth: userData.dateOfBirth,
address: userData.address,
real_photo: userData.photoBase64,
document_number: userData.documentNumber,
files: {
imgs: userData.additionalFiles
}
}, {
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json'
}
});
if (response.status === 200) {
console.log('✅ Digital ID request created successfully');
return response.data;
}
} catch (error) {
console.error('Failed to create Digital ID request:', error.response?.data || error.message);
throw error;
}
}
// Get Digital ID information
async getDigitalIDInfo() {
try {
const response = await axios.get(`${this.baseUrl}/account/v1/did/`, {
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json'
}
});
if (response.status === 200) {
const digitalID = response.data.data[0];
this.digitalIDs.set(digitalID.id, digitalID);
return digitalID;
}
} catch (error) {
console.error('Failed to get Digital ID info:', error.response?.data || error.message);
throw error;
}
}
// Get public encryption key
async getPublicKey() {
try {
const response = await axios.get(`${this.baseUrl}/utils/v1/public-key/`);
if (response.status === 200) {
return response.data;
}
} catch (error) {
console.error('Failed to get public key:', error.response?.data || error.message);
throw error;
}
}
// Generate encrypted QR code
async generateEncryptedQRCode(digitalIDData) {
try {
// Get current public key
const keyData = await this.getPublicKey();
// Prepare QR code data structure
const qrData = {
qr_code_data_real: {
id: digitalIDData.id,
username: digitalIDData.username,
first_name: digitalIDData.first_name,
last_name: digitalIDData.last_name,
third_name: digitalIDData.third_name,
date_of_birth: digitalIDData.date_of_birth,
gender: digitalIDData.gender,
nationality: digitalIDData.nationality
},
qr_code_data_contact: {
main_email: digitalIDData.main_email,
main_phone: digitalIDData.main_phone
},
qr_code_data_chat: {
is_allowed_direct_chats: true,
data: 'Digital ID contact sharing enabled'
},
qr_code_data_events: [],
qr_code_data_work: []
};
// Encrypt data with AES-256
const encryptedData = this.encryptWithAES(JSON.stringify(qrData), keyData.key);
// Generate QR code
const qrCodeDataURL = await QRCode.toDataURL(encryptedData);
return {
encryptedData,
qrCodeDataURL,
keyTimestamp: keyData.timestamp_start
};
} catch (error) {
console.error('Failed to generate encrypted QR code:', error);
throw error;
}
}
// AES-256 encryption
encryptWithAES(data, key) {
const algorithm = 'aes-256-cbc';
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipher(algorithm, key);
let encrypted = cipher.update(data, 'utf8', 'hex');
encrypted += cipher.final('hex');
return `U2FsdGVkX1${iv.toString('hex')}${encrypted}`;
}
// Decrypt Digital ID data
decryptDigitalIDData(encryptedData, key) {
try {
// Extract IV and encrypted content
const ivHex = encryptedData.substring(12, 44);
const encryptedContent = encryptedData.substring(44);
const iv = Buffer.from(ivHex, 'hex');
const decipher = crypto.createDecipher('aes-256-cbc', key);
let decrypted = decipher.update(encryptedContent, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return JSON.parse(decrypted);
} catch (error) {
console.error('Failed to decrypt Digital ID data:', error);
throw error;
}
}
// Process scanned QR code
async processScannedQRCode(qrCodeData) {
try {
// Check if it's a Digital ID QR code
if (qrCodeData.startsWith('U2FsdGVkX1')) {
const keyData = await this.getPublicKey();
const decryptedData = this.decryptDigitalIDData(qrCodeData, keyData.key);
// Add to contacts
await this.addContactFromDigitalID(decryptedData);
return {
type: 'digital_id',
data: decryptedData,
success: true
};
}
return {
type: 'unknown',
data: null,
success: false
};
} catch (error) {
console.error('Failed to process scanned QR code:', error);
throw error;
}
}
// Add contact from Digital ID
async addContactFromDigitalID(digitalIDData) {
const contact = {
username: digitalIDData.qr_code_data_real.username,
firstName: digitalIDData.qr_code_data_real.first_name,
lastName: digitalIDData.qr_code_data_real.last_name,
thirdName: digitalIDData.qr_code_data_real.third_name,
email: digitalIDData.qr_code_data_contact.main_email,
phone: digitalIDData.qr_code_data_contact.main_phone,
hasDigitalID: true,
isVerified: true,
digitalIDData: digitalIDData
};
// Here you would typically save to your database
console.log('✅ Contact added from Digital ID:', contact.firstName, contact.lastName);
return contact;
}
}
// Usage example
const digitalIDClient = new allgramDigitalIDClient('your-api-key-here');
// Create Digital ID request
const userData = {
firstName: 'John',
lastName: 'Doe',
thirdName: 'Smith',
gender: 'male',
placeOfBirth: 'New York',
nationality: 'US',
dateOfBirth: '1990-01-01',
address: '123 Main St, New York, NY',
photoBase64: 'base64_encoded_photo_data',
documentNumber: 'US123456789',
additionalFiles: []
};
// Initialize Digital ID
digitalIDClient.createDigitalIDRequest(userData)
.then(result => {
console.log('Digital ID request created:', result);
})
.catch(error => {
console.error('Failed to create Digital ID request:', error);
});
Our Node.js integration provides enterprise-grade Digital ID capabilities with minimal setup. Built on proven technologies like Express.js and crypto, it offers exceptional performance and reliability for production applications.
Build native iOS Digital ID applications with Swift and SwiftUI. Our iOS SDK provides seamless integration with UIKit and SwiftUI, QR code scanning, and secure Digital ID management. Perfect for creating professional iOS identity verification applications with modern design patterns.
// allgram Digital ID Swift iOS Integration Example
import SwiftUI
import Combine
import CryptoKit
import AVFoundation
// MARK: - Digital ID Models
struct DigitalID: Codable, Identifiable {
let id: String
let username: String
let firstName: String
let lastName: String
let thirdName: String
let realPhoto: String
let dateOfBirth: String
let gender: String
let nationality: String
let placeOfBirth: String
let address: String
let documentNumber: String
let status: Int
let createdAt: String
let approvedAt: String?
enum CodingKeys: String, CodingKey {
case id
case username
case firstName = "first_name"
case lastName = "last_name"
case thirdName = "third_name"
case realPhoto = "real_photo"
case dateOfBirth = "date_of_birth"
case gender
case nationality
case placeOfBirth = "place_of_birth"
case address
case documentNumber = "document_number"
case status
case createdAt = "created_at"
case approvedAt = "approved_at"
}
}
struct QRCodeData: Codable {
let qrCodeDataReal: QRCodeDataReal
let qrCodeDataContact: QRCodeDataContact
let qrCodeDataChat: QRCodeDataChat
let qrCodeDataEvents: [String]
let qrCodeDataWork: [String]
enum CodingKeys: String, CodingKey {
case qrCodeDataReal = "qr_code_data_real"
case qrCodeDataContact = "qr_code_data_contact"
case qrCodeDataChat = "qr_code_data_chat"
case qrCodeDataEvents = "qr_code_data_events"
case qrCodeDataWork = "qr_code_data_work"
}
}
struct QRCodeDataReal: Codable {
let id: String
let username: String
let firstName: String
let lastName: String
let thirdName: String
let dateOfBirth: String
let gender: String
let nationality: String
enum CodingKeys: String, CodingKey {
case id
case username
case firstName = "first_name"
case lastName = "last_name"
case thirdName = "third_name"
case dateOfBirth = "date_of_birth"
case gender
case nationality
}
}
struct QRCodeDataContact: Codable {
let mainEmail: String?
let mainPhone: String?
enum CodingKeys: String, CodingKey {
case mainEmail = "main_email"
case mainPhone = "main_phone"
}
}
struct QRCodeDataChat: Codable {
let isAllowedDirectChats: Bool
let data: String
enum CodingKeys: String, CodingKey {
case isAllowedDirectChats = "is_allowed_direct_chats"
case data
}
}
// MARK: - Digital ID Service
class allgramDigitalIDService: ObservableObject {
@Published var digitalID: DigitalID?
@Published var isConnected = false
@Published var isLoading = false
private var cancellables = Set<AnyCancellable>()
private let baseURL = "https://api.allgram.best"
private let apiKey: String
init(apiKey: String) {
self.apiKey = apiKey
}
// MARK: - Digital ID Management
func createDigitalIDRequest(userData: [String: Any]) async throws -> DigitalID {
let url = URL(string: "\(baseURL)/account/v1/did/create/")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = try JSONSerialization.data(withJSONObject: userData)
let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse,
httpResponse.statusCode == 200 else {
throw DigitalIDError.serverError
}
let digitalID = try JSONDecoder().decode(DigitalID.self, from: data)
DispatchQueue.main.async {
self.digitalID = digitalID
}
return digitalID
}
func getDigitalIDInfo() async throws -> DigitalID {
let url = URL(string: "\(baseURL)/account/v1/did/")!
var request = URLRequest(url: url)
request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse,
httpResponse.statusCode == 200 else {
throw DigitalIDError.serverError
}
let responseData = try JSONDecoder().decode(DigitalIDResponse.self, from: data)
let digitalID = responseData.data[0]
DispatchQueue.main.async {
self.digitalID = digitalID
}
return digitalID
}
// MARK: - Public Key Management
func getPublicKey() async throws -> PublicKeyData {
let url = URL(string: "\(baseURL)/utils/v1/public-key/")!
let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse,
httpResponse.statusCode == 200 else {
throw DigitalIDError.serverError
}
return try JSONDecoder().decode(PublicKeyData.self, from: data)
}
// MARK: - QR Code Generation
func generateEncryptedQRCode(digitalID: DigitalID) async throws -> String {
let keyData = try await getPublicKey()
let qrData = QRCodeData(
qrCodeDataReal: QRCodeDataReal(
id: digitalID.id,
username: digitalID.username,
firstName: digitalID.firstName,
lastName: digitalID.lastName,
thirdName: digitalID.thirdName,
dateOfBirth: digitalID.dateOfBirth,
gender: digitalID.gender,
nationality: digitalID.nationality
),
qrCodeDataContact: QRCodeDataContact(
mainEmail: nil,
mainPhone: nil
),
qrCodeDataChat: QRCodeDataChat(
isAllowedDirectChats: true,
data: "Digital ID contact sharing enabled"
),
qrCodeDataEvents: [],
qrCodeDataWork: []
)
let jsonData = try JSONEncoder().encode(qrData)
let jsonString = String(data: jsonData, encoding: .utf8)!
return encryptWithAES(jsonString, key: keyData.key)
}
// MARK: - Encryption
private func encryptWithAES(_ data: String, key: String) -> String {
let keyData = key.data(using: .utf8)!
let dataToEncrypt = data.data(using: .utf8)!
let key = SymmetricKey(data: keyData)
let sealedBox = try! AES.GCM.seal(dataToEncrypt, using: key)
let encryptedData = sealedBox.combined!
return "U2FsdGVkX1" + encryptedData.base64EncodedString()
}
// MARK: - QR Code Scanning
func processScannedQRCode(_ qrCodeData: String) async throws -> QRCodeData? {
guard qrCodeData.startsWith("U2FsdGVkX1") else {
return nil
}
let keyData = try await getPublicKey()
let decryptedData = try decryptWithAES(qrCodeData, key: keyData.key)
return try JSONDecoder().decode(QRCodeData.self, from: decryptedData)
}
private func decryptWithAES(_ encryptedData: String, key: String) throws -> Data {
let keyData = key.data(using: .utf8)!
let encryptedData = Data(base64Encoded: String(encryptedData.dropFirst(12)))!
let key = SymmetricKey(data: keyData)
let sealedBox = try AES.GCM.SealedBox(combined: encryptedData)
return try AES.GCM.open(sealedBox, using: key)
}
}
// MARK: - Response Models
struct DigitalIDResponse: Codable {
let data: [DigitalID]
}
struct PublicKeyData: Codable {
let key: String
let timestampStart: String
let timestampEnd: String
enum CodingKeys: String, CodingKey {
case key
case timestampStart = "timestamp_start"
case timestampEnd = "timestamp_end"
}
}
// MARK: - Error Handling
enum DigitalIDError: Error, LocalizedError {
case serverError
case networkError
case authenticationError
case encryptionError
var errorDescription: String? {
switch self {
case .serverError:
return "Server error occurred"
case .networkError:
return "Network connection failed"
case .authenticationError:
return "Authentication failed"
case .encryptionError:
return "Encryption/decryption failed"
}
}
}
// MARK: - SwiftUI Views
struct DigitalIDView: View {
@StateObject private var digitalIDService = allgramDigitalIDService(apiKey: "your-api-key")
@State private var showingQRScanner = false
@State private var scannedData: QRCodeData?
var body: some View {
NavigationView {
VStack(spacing: 20) {
if let digitalID = digitalIDService.digitalID {
DigitalIDCard(digitalID: digitalID)
} else {
CreateDigitalIDButton(digitalIDService: digitalIDService)
}
if let scannedData = scannedData {
ScannedDataView(data: scannedData)
}
Button("Scan QR Code") {
showingQRScanner = true
}
.buttonStyle(.borderedProminent)
}
.navigationTitle("Digital ID")
.sheet(isPresented: $showingQRScanner) {
QRScannerView { qrCode in
Task {
do {
scannedData = try await digitalIDService.processScannedQRCode(qrCode)
} catch {
print("Failed to process QR code: \(error)")
}
}
}
}
}
}
}
struct DigitalIDCard: View {
let digitalID: DigitalID
var body: some View {
VStack(alignment: .leading, spacing: 12) {
HStack {
AsyncImage(url: URL(string: digitalID.realPhoto)) { image in
image.resizable()
} placeholder: {
Image(systemName: "person.circle.fill")
.foregroundColor(.gray)
}
.frame(width: 60, height: 60)
.clipShape(Circle())
VStack(alignment: .leading) {
Text("\(digitalID.firstName) \(digitalID.lastName)")
.font(.title2)
.fontWeight(.bold)
Text("Verified Identity")
.font(.caption)
.foregroundColor(.green)
.padding(.horizontal, 8)
.padding(.vertical, 4)
.background(Color.green.opacity(0.2))
.cornerRadius(4)
}
Spacer()
}
Divider()
VStack(alignment: .leading, spacing: 8) {
InfoRow(label: "Username", value: digitalID.username)
InfoRow(label: "Date of Birth", value: digitalID.dateOfBirth)
InfoRow(label: "Nationality", value: digitalID.nationality)
InfoRow(label: "Status", value: statusText(digitalID.status))
}
}
.padding()
.background(Color(.systemBackground))
.cornerRadius(12)
.shadow(radius: 2)
}
private func statusText(_ status: Int) -> String {
switch status {
case 0: return "Processing"
case 1: return "Approved"
case 2: return "Rejected"
default: return "Unknown"
}
}
}
struct InfoRow: View {
let label: String
let value: String
var body: some View {
HStack {
Text(label)
.foregroundColor(.secondary)
Spacer()
Text(value)
.fontWeight(.medium)
}
}
}
struct CreateDigitalIDButton: View {
let digitalIDService: allgramDigitalIDService
var body: some View {
VStack(spacing: 16) {
Image(systemName: "person.badge.plus")
.font(.system(size: 48))
.foregroundColor(.blue)
Text("Create Digital ID")
.font(.title2)
.fontWeight(.semibold)
Text("Verify your identity and get a secure Digital ID for contact sharing")
.multilineTextAlignment(.center)
.foregroundColor(.secondary)
Button("Get Started") {
// Show Digital ID creation form
}
.buttonStyle(.borderedProminent)
}
.padding()
.background(Color(.systemBackground))
.cornerRadius(12)
.shadow(radius: 2)
}
}
Our Swift SDK leverages the latest iOS technologies including SwiftUI, Combine, and async/await. Built with modern iOS development patterns, it provides a seamless developer experience while maintaining high performance and security standards.
Build powerful Android Digital ID applications with Kotlin and Jetpack Compose. Our Android SDK provides seamless integration with modern Android development tools, QR code scanning, and blockchain-based identity verification. Perfect for creating professional Android Digital ID applications.
// allgram Digital ID Kotlin Android Integration Example
package com.allgram.digitalid
import android.util.Log
import androidx.compose.runtime.*
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import okhttp3.*
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.toRequestBody
import org.json.JSONObject
import java.security.MessageDigest
import javax.crypto.Cipher
import javax.crypto.spec.GCMParameterSpec
import javax.crypto.spec.SecretKeySpec
// MARK: - Data Models
data class DigitalID(
val id: String,
val username: String,
val firstName: String,
val lastName: String,
val thirdName: String,
val realPhoto: String,
val dateOfBirth: String,
val gender: String,
val nationality: String,
val placeOfBirth: String,
val address: String,
val documentNumber: String,
val status: Int,
val createdAt: String,
val approvedAt: String?
)
data class QRCodeData(
val qrCodeDataReal: QRCodeDataReal,
val qrCodeDataContact: QRCodeDataContact,
val qrCodeDataChat: QRCodeDataChat,
val qrCodeDataEvents: List<String>,
val qrCodeDataWork: List<String>
)
data class QRCodeDataReal(
val id: String,
val username: String,
val firstName: String,
val lastName: String,
val thirdName: String,
val dateOfBirth: String,
val gender: String,
val nationality: String
)
data class QRCodeDataContact(
val mainEmail: String?,
val mainPhone: String?
)
data class QRCodeDataChat(
val isAllowedDirectChats: Boolean,
val data: String
)
// MARK: - Digital ID Service
class allgramDigitalIDService(
private val apiKey: String,
private val baseUrl: String = "https://api.allgram.best"
) {
private val client = OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.build()
// MARK: - Digital ID Management
suspend fun createDigitalIDRequest(userData: Map<String, Any>): Result<DigitalID> = withContext(Dispatchers.IO) {
try {
val requestBody = JSONObject().apply {
put("first_name", userData["firstName"])
put("last_name", userData["lastName"])
put("third_name", userData["thirdName"])
put("gender", userData["gender"])
put("place_of_birth", userData["placeOfBirth"])
put("nationality", userData["nationality"])
put("date_of_birth", userData["dateOfBirth"])
put("address", userData["address"])
put("real_photo", userData["photoBase64"])
put("document_number", userData["documentNumber"])
put("files", JSONObject().apply {
put("imgs", JSONArray())
})
}.toString()
val request = Request.Builder()
.url("$baseUrl/account/v1/did/create/")
.post(requestBody.toRequestBody("application/json".toMediaType()))
.addHeader("Authorization", "Bearer $apiKey")
.build()
val response = client.newCall(request).execute()
if (response.isSuccessful) {
val responseBody = response.body?.string()
val digitalIDJson = JSONObject(responseBody ?: "")
val digitalID = DigitalID(
id = digitalIDJson.getString("id"),
username = digitalIDJson.getString("username"),
firstName = digitalIDJson.getString("first_name"),
lastName = digitalIDJson.getString("last_name"),
thirdName = digitalIDJson.optString("third_name", ""),
realPhoto = digitalIDJson.getString("real_photo"),
dateOfBirth = digitalIDJson.getString("date_of_birth"),
gender = digitalIDJson.getString("gender"),
nationality = digitalIDJson.getString("nationality"),
placeOfBirth = digitalIDJson.getString("place_of_birth"),
address = digitalIDJson.getString("address"),
documentNumber = digitalIDJson.getString("document_number"),
status = digitalIDJson.getInt("status"),
createdAt = digitalIDJson.getString("created_at"),
approvedAt = digitalIDJson.optString("approved_at", null)
)
Log.d("allgramDigitalID", "✅ Digital ID request created: ${digitalID.firstName} ${digitalID.lastName}")
Result.success(digitalID)
} else {
Log.e("allgramDigitalID", "Failed to create Digital ID: ${response.code}")
Result.failure(Exception("Server error: ${response.code}"))
}
} catch (e: Exception) {
Log.e("allgramDigitalID", "Exception creating Digital ID", e)
Result.failure(e)
}
}
suspend fun getDigitalIDInfo(): Result<DigitalID> = withContext(Dispatchers.IO) {
try {
val request = Request.Builder()
.url("$baseUrl/account/v1/did/")
.addHeader("Authorization", "Bearer $apiKey")
.build()
val response = client.newCall(request).execute()
if (response.isSuccessful) {
val responseBody = response.body?.string()
val responseJson = JSONObject(responseBody ?: "")
val digitalIDArray = responseJson.getJSONArray("data")
val digitalIDJson = digitalIDArray.getJSONObject(0)
val digitalID = DigitalID(
id = digitalIDJson.getString("id"),
username = digitalIDJson.getString("username"),
firstName = digitalIDJson.getString("first_name"),
lastName = digitalIDJson.getString("last_name"),
thirdName = digitalIDJson.optString("third_name", ""),
realPhoto = digitalIDJson.getString("real_photo"),
dateOfBirth = digitalIDJson.getString("date_of_birth"),
gender = digitalIDJson.getString("gender"),
nationality = digitalIDJson.getString("nationality"),
placeOfBirth = digitalIDJson.getString("place_of_birth"),
address = digitalIDJson.getString("address"),
documentNumber = digitalIDJson.getString("document_number"),
status = digitalIDJson.getInt("status"),
createdAt = digitalIDJson.getString("created_at"),
approvedAt = digitalIDJson.optString("approved_at", null)
)
Result.success(digitalID)
} else {
Log.e("allgramDigitalID", "Failed to get Digital ID: ${response.code}")
Result.failure(Exception("Server error: ${response.code}"))
}
} catch (e: Exception) {
Log.e("allgramDigitalID", "Exception getting Digital ID", e)
Result.failure(e)
}
}
// MARK: - Public Key Management
suspend fun getPublicKey(): Result<PublicKeyData> = withContext(Dispatchers.IO) {
try {
val request = Request.Builder()
.url("$baseUrl/utils/v1/public-key/")
.build()
val response = client.newCall(request).execute()
if (response.isSuccessful) {
val responseBody = response.body?.string()
val keyJson = JSONObject(responseBody ?: "")
val publicKeyData = PublicKeyData(
key = keyJson.getString("key"),
timestampStart = keyJson.getString("timestamp_start"),
timestampEnd = keyJson.getString("timestamp_end")
)
Result.success(publicKeyData)
} else {
Log.e("allgramDigitalID", "Failed to get public key: ${response.code}")
Result.failure(Exception("Server error: ${response.code}"))
}
} catch (e: Exception) {
Log.e("allgramDigitalID", "Exception getting public key", e)
Result.failure(e)
}
}
// MARK: - QR Code Generation
suspend fun generateEncryptedQRCode(digitalID: DigitalID): Result<String> = withContext(Dispatchers.IO) {
try {
val keyResult = getPublicKey()
if (keyResult.isFailure) {
return Result.failure(keyResult.exceptionOrNull() ?: Exception("Failed to get public key"))
}
val keyData = keyResult.getOrNull()!!
val qrData = QRCodeData(
qrCodeDataReal = QRCodeDataReal(
id = digitalID.id,
username = digitalID.username,
firstName = digitalID.firstName,
lastName = digitalID.lastName,
thirdName = digitalID.thirdName,
dateOfBirth = digitalID.dateOfBirth,
gender = digitalID.gender,
nationality = digitalID.nationality
),
qrCodeDataContact = QRCodeDataContact(
mainEmail = null,
mainPhone = null
),
qrCodeDataChat = QRCodeDataChat(
isAllowedDirectChats = true,
data = "Digital ID contact sharing enabled"
),
qrCodeDataEvents = emptyList(),
qrCodeDataWork = emptyList()
)
val jsonData = JSONObject().apply {
put("qr_code_data_real", JSONObject().apply {
put("id", qrData.qrCodeDataReal.id)
put("username", qrData.qrCodeDataReal.username)
put("first_name", qrData.qrCodeDataReal.firstName)
put("last_name", qrData.qrCodeDataReal.lastName)
put("third_name", qrData.qrCodeDataReal.thirdName)
put("date_of_birth", qrData.qrCodeDataReal.dateOfBirth)
put("gender", qrData.qrCodeDataReal.gender)
put("nationality", qrData.qrCodeDataReal.nationality)
})
put("qr_code_data_contact", JSONObject().apply {
put("main_email", JSONObject.NULL)
put("main_phone", JSONObject.NULL)
})
put("qr_code_data_chat", JSONObject().apply {
put("is_allowed_direct_chats", qrData.qrCodeDataChat.isAllowedDirectChats)
put("data", qrData.qrCodeDataChat.data)
})
put("qr_code_data_events", JSONArray())
put("qr_code_data_work", JSONArray())
}.toString()
val encryptedData = encryptWithAES(jsonData, keyData.key)
Result.success(encryptedData)
} catch (e: Exception) {
Log.e("allgramDigitalID", "Exception generating QR code", e)
Result.failure(e)
}
}
// MARK: - Encryption
private fun encryptWithAES(data: String, key: String): String {
val cipher = Cipher.getInstance("AES/GCM/NoPadding")
val secretKey = SecretKeySpec(key.toByteArray(), "AES")
val iv = ByteArray(12).apply {
java.security.SecureRandom().nextBytes(this)
}
val gcmSpec = GCMParameterSpec(128, iv)
cipher.init(Cipher.ENCRYPT_MODE, secretKey, gcmSpec)
val encrypted = cipher.doFinal(data.toByteArray())
val combined = iv + encrypted
return "U2FsdGVkX1" + android.util.Base64.encodeToString(combined, android.util.Base64.NO_WRAP)
}
// MARK: - QR Code Processing
suspend fun processScannedQRCode(qrCodeData: String): Result<QRCodeData?> = withContext(Dispatchers.IO) {
try {
if (!qrCodeData.startsWith("U2FsdGVkX1")) {
return Result.success(null)
}
val keyResult = getPublicKey()
if (keyResult.isFailure) {
return Result.failure(keyResult.exceptionOrNull() ?: Exception("Failed to get public key"))
}
val keyData = keyResult.getOrNull()!!
val decryptedData = decryptWithAES(qrCodeData, keyData.key)
val jsonObject = JSONObject(decryptedData)
val qrCodeData = parseQRCodeData(jsonObject)
Result.success(qrCodeData)
} catch (e: Exception) {
Log.e("allgramDigitalID", "Exception processing QR code", e)
Result.failure(e)
}
}
private fun decryptWithAES(encryptedData: String, key: String): String {
val encryptedBytes = android.util.Base64.decode(encryptedData.substring(12), android.util.Base64.NO_WRAP)
val iv = encryptedBytes.sliceArray(0..11)
val encrypted = encryptedBytes.sliceArray(12 until encryptedBytes.size)
val cipher = Cipher.getInstance("AES/GCM/NoPadding")
val secretKey = SecretKeySpec(key.toByteArray(), "AES")
val gcmSpec = GCMParameterSpec(128, iv)
cipher.init(Cipher.DECRYPT_MODE, secretKey, gcmSpec)
val decrypted = cipher.doFinal(encrypted)
return String(decrypted)
}
private fun parseQRCodeData(json: JSONObject): QRCodeData {
val realData = json.getJSONObject("qr_code_data_real")
val contactData = json.getJSONObject("qr_code_data_contact")
val chatData = json.getJSONObject("qr_code_data_chat")
val eventsArray = json.getJSONArray("qr_code_data_events")
val workArray = json.getJSONArray("qr_code_data_work")
return QRCodeData(
qrCodeDataReal = QRCodeDataReal(
id = realData.getString("id"),
username = realData.getString("username"),
firstName = realData.getString("first_name"),
lastName = realData.getString("last_name"),
thirdName = realData.optString("third_name", ""),
dateOfBirth = realData.getString("date_of_birth"),
gender = realData.getString("gender"),
nationality = realData.getString("nationality")
),
qrCodeDataContact = QRCodeDataContact(
mainEmail = contactData.optString("main_email", null),
mainPhone = contactData.optString("main_phone", null)
),
qrCodeDataChat = QRCodeDataChat(
isAllowedDirectChats = chatData.getBoolean("is_allowed_direct_chats"),
data = chatData.getString("data")
),
qrCodeDataEvents = List(eventsArray.length()) { i -> eventsArray.getString(i) },
qrCodeDataWork = List(workArray.length()) { i -> workArray.getString(i) }
)
}
}
// MARK: - Response Models
data class PublicKeyData(
val key: String,
val timestampStart: String,
val timestampEnd: String
)
// MARK: - ViewModel
class DigitalIDViewModel(
private val digitalIDService: allgramDigitalIDService
) : ViewModel() {
private val _digitalID = MutableStateFlow<DigitalID?>(null)
val digitalID: StateFlow<DigitalID?> = _digitalID.asStateFlow()
private val _isLoading = MutableStateFlow(false)
val isLoading: StateFlow<Boolean> = _isLoading.asStateFlow()
private val _scannedData = MutableStateFlow<QRCodeData?>(null)
val scannedData: StateFlow<QRCodeData?> = _scannedData.asStateFlow()
init {
loadDigitalID()
}
private fun loadDigitalID() {
viewModelScope.launch {
_isLoading.value = true
try {
val result = digitalIDService.getDigitalIDInfo()
result.onSuccess { digitalID ->
_digitalID.value = digitalID
}.onFailure { error ->
Log.e("DigitalIDViewModel", "Failed to load Digital ID", error)
}
} finally {
_isLoading.value = false
}
}
}
fun createDigitalIDRequest(userData: Map<String, Any>) {
viewModelScope.launch {
_isLoading.value = true
try {
val result = digitalIDService.createDigitalIDRequest(userData)
result.onSuccess { digitalID ->
_digitalID.value = digitalID
}.onFailure { error ->
Log.e("DigitalIDViewModel", "Failed to create Digital ID", error)
}
} finally {
_isLoading.value = false
}
}
}
fun processScannedQRCode(qrCodeData: String) {
viewModelScope.launch {
try {
val result = digitalIDService.processScannedQRCode(qrCodeData)
result.onSuccess { data ->
_scannedData.value = data
}.onFailure { error ->
Log.e("DigitalIDViewModel", "Failed to process QR code", error)
}
} catch (e: Exception) {
Log.e("DigitalIDViewModel", "Exception processing QR code", e)
}
}
}
}
// MARK: - Compose UI
@Composable
fun DigitalIDScreen(
viewModel: DigitalIDViewModel = viewModel { DigitalIDViewModel(allgramDigitalIDService("your-api-key")) }
) {
val digitalID by viewModel.digitalID.collectAsState()
val isLoading by viewModel.isLoading.collectAsState()
val scannedData by viewModel.scannedData.collectAsState()
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
) {
if (isLoading) {
CircularProgressIndicator(
modifier = Modifier.align(Alignment.CenterHorizontally)
)
} else if (digitalID != null) {
DigitalIDCard(digitalID = digitalID!!)
} else {
CreateDigitalIDButton(
onCreateRequest = { userData ->
viewModel.createDigitalIDRequest(userData)
}
)
}
if (scannedData != null) {
ScannedDataCard(data = scannedData!!)
}
Button(
onClick = { /* Launch QR scanner */ },
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 16.dp)
) {
Icon(
imageVector = Icons.Default.QrCodeScanner,
contentDescription = "Scan QR Code"
)
Spacer(modifier = Modifier.width(8.dp))
Text("Scan QR Code")
}
}
}
@Composable
fun DigitalIDCard(digitalID: DigitalID) {
Card(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 8.dp),
elevation = CardDefaults.cardElevation(defaultElevation = 4.dp)
) {
Column(
modifier = Modifier.padding(16.dp)
) {
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
AsyncImage(
model = digitalID.realPhoto,
contentDescription = "Profile Photo",
modifier = Modifier
.size(60.dp)
.clip(CircleShape)
)
Spacer(modifier = Modifier.width(16.dp))
Column {
Text(
text = "${digitalID.firstName} ${digitalID.lastName}",
style = MaterialTheme.typography.h6
)
Text(
text = "Verified Identity",
style = MaterialTheme.typography.caption,
color = Color.Green
)
}
}
Spacer(modifier = Modifier.height(16.dp))
InfoRow(label = "Username", value = digitalID.username)
InfoRow(label = "Date of Birth", value = digitalID.dateOfBirth)
InfoRow(label = "Nationality", value = digitalID.nationality)
InfoRow(label = "Status", value = getStatusText(digitalID.status))
}
}
}
@Composable
fun InfoRow(label: String, value: String) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 4.dp),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
text = label,
style = MaterialTheme.typography.body2,
color = MaterialTheme.colors.onSurface.copy(alpha = 0.6f)
)
Text(
text = value,
style = MaterialTheme.typography.body2,
fontWeight = FontWeight.Medium
)
}
}
private fun getStatusText(status: Int): String {
return when (status) {
0 -> "Processing"
1 -> "Approved"
2 -> "Rejected"
else -> "Unknown"
}
}
Our Kotlin SDK leverages the latest Android technologies including Jetpack Compose, Coroutines, and modern Android architecture patterns. Built with performance and developer experience in mind, it provides a robust foundation for building scalable Digital ID applications.
Ready to take your Digital ID integration to the next level? Explore our comprehensive resources and advanced features to build enterprise-grade identity verification applications with allgram.
Learn about our enterprise security features, GDPR compliance, and blockchain-based verification.
Learn More →Discover advanced techniques for optimizing Digital ID performance and scalability.
Learn More →Join our developer community for support, updates, and collaboration.
Join Community →