Skip to main content

Cosmic Cipher Password Generator

This recipe demonstrates how to build a secure password generator using SpaceComputer Orbitport's cTRNG (cosmic True Random Number Generator) service. Unlike traditional password generators that rely on pseudo-random algorithms, this implementation uses genuine cosmic randomness from satellite instrumentation to create truly unpredictable passwords.

Prerequisites

  • TypeScript/JavaScript knowledge
  • Next.js or React application
  • API access to SpaceComputer Orbitport (Get your API access key here)
  • Understanding of password security requirements

What You'll Build

A secure password generator that:

  • Uses cosmic randomness from satellite instrumentation for true entropy
  • Implements flexible password generation with customizable character sets
  • Provides client-side password generation with server-side randomness
  • Includes fallback mechanisms for offline resilience
  • Offers verifiable randomness with seed display

🏗️ Architecture Pattern Rationale

This recipe implements a Hybrid Randomness Pattern which is ideal for password generation:

  • Cosmic Entropy: Server-side retrieval of truly random seeds from space
  • Local Generation: Client-side password crafting for flexibility and privacy
  • Fallback Resilience: Node.js crypto fallback when cosmic randomness is unavailable
  • Verifiable Randomness: Users can verify the cosmic origin of their passwords
  • Customizable Logic: Easy to modify character sets and generation rules

Implementation Steps

1. Environment Configuration

Set up your environment variables:

# .env.local
ORBITPORT_CLIENT_ID=your_client_id
ORBITPORT_CLIENT_SECRET=your_client_secret
ORBITPORT_AUTH_URL=https://auth.spacecomputer.io
ORBITPORT_API_URL=https://op.spacecomputer.io

2. Authentication Setup

🎯 Design Rationale for Production

Server-side authentication is critical for password generation because:

  • Security: API credentials are never exposed to client-side code, preventing credential theft
  • Token Management: Centralized token lifecycle management reduces security vulnerabilities
  • Rate Limiting: Server-side control allows for proper API rate limiting and abuse prevention
  • Audit Trail: All password generation requests can be logged and monitored
  • Scalability: Multiple server instances can share the same authentication logic

Create a centralized authentication utility in lib/auth.ts:

// lib/auth.ts
import { NextApiRequest, NextApiResponse } from "next";
import { parseToken, decrypt, encrypt } from "./crypto"; // You'll need to implement these

const TOKEN_EXPIRE_BUFFER = 300; // 5 minutes buffer

async function generateAccessToken(): Promise<string | null> {
const clientId = process.env.ORBITPORT_CLIENT_ID;
const clientSecret = process.env.ORBITPORT_CLIENT_SECRET;
const authUrl = process.env.ORBITPORT_AUTH_URL;

if (!clientId || !clientSecret || !authUrl) {
throw new Error("Missing Orbitport authentication configuration");
}

try {
const response = await fetch(`${authUrl}/oauth/token`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
client_id: clientId,
client_secret: clientSecret,
audience: "https://op.spacecomputer.io/api",
grant_type: "client_credentials",
}),
});

if (!response.ok) {
throw new Error("Failed to get access token");
}

const data = await response.json();
return data.access_token;
} catch (error) {
console.error("Error getting access token:", error);
return null;
}
}

export async function getValidToken(
req: NextApiRequest,
res: NextApiResponse
): Promise<string | null> {
try {
const encryptedToken = getEncryptedTokenFromCookies(req);
let accessToken: string | null = null;

if (encryptedToken) {
const decrypted = decrypt(encryptedToken);
const parsed = parseToken(decrypted);
if (parsed) {
const now = Math.floor(Date.now() / 1000);
// Only use token if not expired and not about to expire
if (parsed.exp > now + TOKEN_EXPIRE_BUFFER) {
accessToken = parsed.access_token;
}
}
}

// If no valid token, generate a new one
if (!accessToken) {
accessToken = await generateAccessToken();
if (!accessToken) {
console.error("Failed to get new access token");
return null;
}
const parsed = parseToken(accessToken);
if (!parsed) {
console.error("Failed to parse new token");
return null;
}
setEncryptedTokenCookie(res, accessToken, parsed.exp);
}

return accessToken;
} catch (error) {
console.error("Error in getValidToken:", error);
return null;
}
}

🔐 Token Expiry Management Rationale

The TOKEN_EXPIRE_BUFFER (5-minute buffer) is essential for production because:

  • Proactive Refresh: Tokens are refreshed before they expire, preventing user-facing errors
  • Graceful Degradation: If token refresh fails, the buffer provides time for fallback mechanisms
  • Load Distribution: Staggered token refreshes prevent all users from hitting the auth endpoint simultaneously
  • Security: Reduces the window where expired tokens might be used
  • User Experience: Eliminates authentication timeouts during active user sessions

3. API Route for Random Seeds

Create an API endpoint in pages/api/random.ts with fallback support:

// pages/api/random.ts
import { NextApiRequest, NextApiResponse } from "next";
import { getValidToken } from "@/lib/auth";
import crypto from "crypto";

const ORBITPORT_API_URL = process.env.ORBITPORT_API_URL;

export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
let usedFallback = false;
let data: any = null;

try {
if (req.method !== "GET") {
return res.status(405).json({ message: "Method not allowed" });
}

if (!process.env.ORBITPORT_API_URL) {
return res.status(500).json({ message: "Missing Orbitport API URL" });
}

// Get valid token using our auth utility
const accessToken = await getValidToken(req, res);
if (!accessToken) {
return res.status(401).json({ message: "Authentication failed" });
}

// Call downstream API with access token
const response = await fetch(`${ORBITPORT_API_URL}/api/v1/services/trng`, {
headers: {
Authorization: `Bearer ${accessToken}`,
},
});

if (!response.ok) {
const errorText = await response.text();
console.error("Orbitport API error:", errorText);
throw new Error(`API request failed: ${response.status}`);
}

data = await response.json();
} catch (error) {
console.warn("Using fallback random generation:", error);
usedFallback = true;

// Fallback to Node.js crypto for offline resilience
const fallbackSeed = crypto.randomBytes(32).toString("hex");
data = {
service: "fallback",
src: "node-crypto",
data: fallbackSeed,
signature: {
value: "fallback-signature",
pk: "fallback-key",
},
};
}

return res.status(200).json({
...data,
usedFallback,
});
}

🌐 API Route Design Rationale

Using a server-side API route with fallback provides:

  • Security: Access tokens never leave your server, preventing token exposure
  • Error Handling: Centralized error handling with proper HTTP status codes
  • Fallback Resilience: Node.js crypto ensures password generation works even when cosmic randomness is unavailable
  • Rate Limiting: Implement per-user rate limiting to prevent API abuse
  • Monitoring: Track usage patterns and implement alerting for production issues
  • Compliance: Meet enterprise security requirements for external API access

4. Password Generation Logic

Create the core password generation logic in lib/password-generator.ts:

// lib/password-generator.ts

interface GenerateParams {
length: number;
minUpper: number;
minLower: number;
minNumbers: number;
minSymbols: number;
includeUpper: boolean;
includeLower: boolean;
includeNumbers: boolean;
includeSymbols: boolean;
}

const CHARSETS = {
uppercase: "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
lowercase: "abcdefghijklmnopqrstuvwxyz",
numbers: "0123456789",
symbols: "!@#$%^&*+-=",
};

// Creates a deterministic random generator from cosmic seed
function createRandomGenerator(seed: string) {
const seedBytes = new Uint8Array(Buffer.from(seed, "hex"));
let position = 0;
return (length: number): Uint8Array => {
const result = new Uint8Array(length);
for (let i = 0; i < length; i++) {
result[i] = seedBytes[position % seedBytes.length];
position++;
}
return result;
};
}

export function generatePasswordFromSeed(
seed: string,
params: GenerateParams
): string {
const randomValues = createRandomGenerator(seed);
const {
length,
minUpper,
minLower,
minNumbers,
minSymbols,
includeUpper,
includeLower,
includeNumbers,
includeSymbols,
} = params;

// Build character sets based on user selection
const availableCharsets: { [key: string]: string } = {};
if (includeUpper) availableCharsets.uppercase = CHARSETS.uppercase;
if (includeLower) availableCharsets.lowercase = CHARSETS.lowercase;
if (includeNumbers) availableCharsets.numbers = CHARSETS.numbers;
if (includeSymbols) availableCharsets.symbols = CHARSETS.symbols;

// Generate password meeting minimum requirements
let password = "";
if (includeUpper) {
for (let i = 0; i < minUpper; i++) {
password +=
availableCharsets.uppercase[
randomValues(1)[0] % availableCharsets.uppercase.length
];
}
}
if (includeLower) {
for (let i = 0; i < minLower; i++) {
password +=
availableCharsets.lowercase[
randomValues(1)[0] % availableCharsets.lowercase.length
];
}
}
if (includeNumbers) {
for (let i = 0; i < minNumbers; i++) {
password +=
availableCharsets.numbers[
randomValues(1)[0] % availableCharsets.numbers.length
];
}
}
if (includeSymbols) {
for (let i = 0; i < minSymbols; i++) {
password +=
availableCharsets.symbols[
randomValues(1)[0] % availableCharsets.symbols.length
];
}
}

// Fill remaining length with random chars
const allAvailableChars = Object.values(availableCharsets).join("");
const remainingLength = length - password.length;
for (let i = 0; i < remainingLength; i++) {
password +=
allAvailableChars[randomValues(1)[0] % allAvailableChars.length];
}

// Fisher-Yates shuffle using cosmic seed for randomness
const passwordArray = password.split("");
for (let i = passwordArray.length - 1; i > 0; i--) {
const j = randomValues(1)[0] % (i + 1);
[passwordArray[i], passwordArray[j]] = [passwordArray[j], passwordArray[i]];
}

return passwordArray.join("");
}

🔐 Password Generation Rationale

The password generation logic provides production benefits through:

  • Cosmic Entropy: Uses genuine randomness from space, not predictable algorithms
  • Deterministic Mapping: Same seed always produces the same password for verification
  • Requirement Fulfillment: Guarantees minimum character requirements are met
  • Fair Distribution: Fisher-Yates shuffle ensures uniform character distribution
  • Extensibility: Easy to add new character sets or modify generation rules
  • Client-Side Privacy: Password generation happens locally, not on external servers

5. Client-Side Hook

Create a custom React hook in hooks/useOrbitport.ts:

// hooks/useOrbitport.ts
import { useCallback } from "react";

interface RandomSeedResponse {
service: string;
src: string;
data: string;
signature: {
value: string;
pk: string;
};
usedFallback: boolean;
}

export function useOrbitport() {
const getRandomSeed = useCallback(async (): Promise<RandomSeedResponse> => {
try {
const response = await fetch("/api/random");
if (!response.ok) {
throw new Error("Failed to get random seed");
}

const data = await response.json();
return data;
} catch (error) {
console.error("Error getting random seed:", error);
throw error;
}
}, []);

return {
getRandomSeed,
};
}

⚛️ React Hook Design Rationale

Custom hooks provide production benefits through:

  • Reusability: The same hook can be used across multiple components
  • State Management: Centralized loading and error states for better UX
  • Testing: Easier to unit test business logic separately from UI components
  • Performance: useCallback prevents unnecessary re-renders and API calls
  • Error Boundaries: Consistent error handling across the application
  • Type Safety: TypeScript interfaces ensure data consistency

6. Usage Example

Here's how to use the password generator in your application:

import { useOrbitport } from "@/hooks/useOrbitport";
import { generatePasswordFromSeed } from "@/lib/password-generator";

function PasswordGenerator() {
const { getRandomSeed } = useOrbitport();
const [password, setPassword] = useState<string>("");
const [seed, setSeed] = useState<string>("");
const [usedFallback, setUsedFallback] = useState<boolean>(false);

const handleGenerate = async () => {
try {
// Fetch cosmic seed from API
const seedResult = await getRandomSeed();

// Generate password client-side using the seed
const generatedPassword = generatePasswordFromSeed(seedResult.data, {
length: 16,
minUpper: 2,
minLower: 2,
minNumbers: 2,
minSymbols: 2,
includeUpper: true,
includeLower: true,
includeNumbers: true,
includeSymbols: true,
});

setPassword(generatedPassword);
setSeed(seedResult.data);
setUsedFallback(seedResult.usedFallback);
} catch (error) {
console.error("Failed to generate password:", error);
}
};

return (
<div>
<button onClick={handleGenerate}>Generate Cosmic Password</button>
{password && (
<div>
<p>
<strong>Password:</strong> {password}
</p>
<p>
<strong>Cosmic Seed:</strong> {seed}
</p>
{usedFallback && (
<p>
<em>Note: Used fallback randomness</em>
</p>
)}
</div>
)}
</div>
);
}

🎲 Password Generation Usage Rationale

The password generator example demonstrates production-ready patterns:

  • Verifiable Randomness: Users can see the cosmic seed that generated their password
  • Fallback Transparency: Clear indication when fallback randomness is used
  • Error Handling: Try-catch blocks prevent application crashes from API failures
  • User Feedback: Clear display of generated password and source randomness
  • Extensibility: Easy to modify character requirements or add new features
  • Security: Password generation happens client-side for privacy

Key Benefits

  • True Randomness: Leverages cosmic radiation for unbiased password generation
  • Security: Server-side token management with client-side password generation
  • Reliability: Fallback mechanisms ensure password generation always works
  • Verifiability: Users can verify the cosmic origin of their passwords
  • Flexibility: Customizable character sets and generation rules
  • Privacy: Password generation happens locally, not on external servers

Use Cases

  • Enterprise Security: Generate secure passwords for corporate accounts
  • Personal Use: Create strong passwords for personal accounts
  • Developer Tools: Integrate into password management systems
  • Security Audits: Generate test passwords with verifiable randomness
  • Compliance: Meet security requirements for password generation

Production Considerations

🚀 Enterprise-Grade Password Security

This recipe follows production-ready patterns essential for secure password generation:

Security First Approach

  • Cosmic Entropy: Uses genuine randomness from space, not predictable algorithms
  • Credential Isolation: API keys are never exposed to client-side code
  • Token Encryption: Access tokens are encrypted in cookies with proper expiry management
  • Client-Side Generation: Passwords are generated locally for privacy

Reliability & Performance

  • Fallback Resilience: Node.js crypto ensures password generation works offline
  • Proactive Token Refresh: Eliminates authentication timeouts during user sessions
  • Error Handling: Graceful degradation when external services are unavailable
  • Performance: Efficient password generation with minimal computational overhead

Scalability & Monitoring

  • Centralized Logic: Single source of truth for authentication across all server instances
  • Performance Metrics: Track API response times and failure rates
  • Alerting: Proactive notifications for authentication failures or rate limit issues
  • Horizontal Scaling: Authentication logic works seamlessly across multiple servers

Compliance & Governance

  • Data Privacy: No sensitive data leaves your infrastructure
  • Audit Trails: Complete logging for compliance and security investigations
  • Rate Limiting: Prevent abuse and ensure fair usage across all users
  • Verifiable Randomness: Users can verify the cosmic origin of their passwords

Next Steps

  • Implement the crypto utility functions for token encryption/decryption
  • Add password strength validation and entropy calculation
  • Consider implementing password history and reuse prevention
  • Explore other Orbitport services like spaceTEE for secure computation
  • Add support for passphrase generation and mnemonic phrases

Resources