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:
useCallbackprevents 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