Dilip Singh logo
All posts
SaaS ArchitectureAdvanced2025-01-05·14 min read

BYOK AI SaaS Architecture: AES-256, Multi-Tenancy & LLM Adapters

How I architected Hureka AI — a BYOK (Bring Your Own Key) multi-tenant AI SaaS. AES-256 encryption for API keys, and a unified LLM adapter pattern for Anthropic, OpenAI, Google, and Ollama.

What is BYOK?

BYOK (Bring Your Own Key) means customers connect their own LLM API keys. Your SaaS platform never stores raw keys — instead you encrypt them before storage and decrypt only at runtime during inference.

This is critical for enterprise customers who have their own OpenAI Enterprise contracts, Anthropic API access, or want to run Ollama on-premise.

Encryption Architecture

typescript
import { createCipheriv, createDecipheriv, randomBytes } from 'crypto'

const MASTER_KEY = Buffer.from(process.env.MASTER_ENCRYPTION_KEY!, 'hex')

export function encryptApiKey(plaintext: string): string { const iv = randomBytes(16) const cipher = createCipheriv('aes-256-gcm', MASTER_KEY, iv)

const encrypted = Buffer.concat([ cipher.update(plaintext, 'utf8'), cipher.final() ]) const authTag = cipher.getAuthTag()

return Buffer.concat([iv, authTag, encrypted]).toString('base64') }

export function decryptApiKey(ciphertext: string): string { const data = Buffer.from(ciphertext, 'base64') const iv = data.subarray(0, 16) const authTag = data.subarray(16, 32) const encrypted = data.subarray(32)

const decipher = createDecipheriv('aes-256-gcm', MASTER_KEY, iv) decipher.setAuthTag(authTag)

return Buffer.concat([decipher.update(encrypted), decipher.final()]).toString('utf8') } ```

The Unified LLM Adapter Pattern

typescript
interface LLMAdapter {
  complete(messages: Message[], options: CompletionOptions): Promise<string>
  stream(messages: Message[], options: CompletionOptions): AsyncGenerator<string>
}

class AnthropicAdapter implements LLMAdapter { private client: Anthropic constructor(apiKey: string) { this.client = new Anthropic({ apiKey }) } async complete(messages: Message[]) { / ... / } }

function createAdapter(org: Organization): LLMAdapter { const key = org.llmProvider === 'ollama' ? '' : decryptApiKey(org.encryptedApiKey) switch (org.llmProvider) { case 'anthropic': return new AnthropicAdapter(key) case 'openai': return new OpenAIAdapter(key) case 'google': return new GoogleAdapter(key) case 'ollama': return new OllamaAdapter(org.ollamaUrl, org.ollamaModel) } } ```

Multi-Tenant Data Isolation

Every database query is filtered by organizationId via Prisma middleware:

typescript
prisma.$use(async (params, next) => {
  if (params.action === 'findMany' || params.action === 'findFirst') {
    params.args.where = {
      ...params.args.where,
      organizationId: getCurrentOrganizationId()
    }
  }
  return next(params)
})

Security Checklist for BYOK SaaS

  1. 1Master key rotation — Support rotating the master encryption key without re-encrypting all tenant keys at once.
  2. 2Audit every decryption — Log when, by whom, and for what purpose each key was decrypted.
  3. 3Short-lived decrypted values — Keep decrypted API keys in memory only for the duration of a single request; never persist them.
  4. 4Separate key storage — Store encrypted keys in your application database, but store the master key in a secrets manager (AWS Secrets Manager, Vault).
DS
Dilip Singh
Lead Software Architect · Hureka Technologies

14+ years building enterprise software and AI systems. Architecting multi-agent AI platforms, RAG pipelines, voice AI, and high-performance SaaS for global clients.