├── apple-sign-in └── generate-apple-secret.ts ├── basic-form └── form.tsx ├── expo-auth-flow ├── components │ ├── Button.tsx │ └── ThemedText.tsx ├── icons │ ├── AppleIcon.tsx │ ├── GoogleIcon.tsx │ └── MailIcon.tsx └── index.tsx ├── fadein-wrapper.tsx ├── floating-navbar ├── Button.tsx ├── Card.tsx ├── Iconify.tsx └── Navbar.tsx └── pulsing-button ├── Button.tsx └── style.css /apple-sign-in/generate-apple-secret.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Apple Client Secret Generator Script 3 | * 4 | * This script generates a client secret JWT required for Apple Sign In authentication. 5 | * The generated secret is valid for 6 months and needs to be regenerated before expiry. 6 | * 7 | * Required Environment Variables in .env: 8 | * - APPLE_TEAM_ID: Found in your Apple Developer account 9 | * - APPLE_KEY_ID: The Key ID from your private key in Apple Developer Console 10 | * - APPLE_CLIENT_ID: Your app's identifier (e.g., com.yourapp.id) 11 | * - APPLE_PRIVATE_KEY_PATH: Path to your .p8 private key file 12 | * 13 | * Important Notes: 14 | * - The private key (.p8) file must be kept secure and never committed to version control 15 | * - The generated secret is valid for 6 months 16 | * - This secret is required for the auth.ts configuration (Better Auth) 17 | * 18 | * To run this script: 19 | * 1. Run the script: npm run generate-apple-secret 20 | * 2. The generated secret will be printed to the console 21 | * 3. Copy the secret and paste it into your .env file 22 | * 4. Restart your server 23 | */ 24 | 25 | import dotenv from "dotenv"; 26 | import fs from "fs"; 27 | import pkg from "jsonwebtoken"; 28 | import path from "path"; 29 | const { sign } = pkg; 30 | 31 | // Load environment variables from .env file 32 | dotenv.config(); 33 | 34 | // Log environment variables for verification 35 | // These logs help debug missing or incorrect values 36 | console.log("Environment variables:"); 37 | console.log("TEAM_ID:", process.env.APPLE_TEAM_ID); 38 | console.log("KEY_ID:", process.env.APPLE_KEY_ID); 39 | console.log("CLIENT_ID:", process.env.APPLE_CLIENT_ID); 40 | console.log("PRIVATE_KEY_PATH:", process.env.APPLE_PRIVATE_KEY_PATH); 41 | 42 | // Extract required configuration from environment 43 | const TEAM_ID = process.env.APPLE_TEAM_ID; 44 | const KEY_ID = process.env.APPLE_KEY_ID; 45 | const CLIENT_ID = process.env.APPLE_CLIENT_ID; 46 | const PRIVATE_KEY_PATH = process.env.APPLE_PRIVATE_KEY_PATH; 47 | 48 | // Validate all required environment variables 49 | // Exit early if any required variable is missing 50 | if (!TEAM_ID || !KEY_ID || !CLIENT_ID || !PRIVATE_KEY_PATH) { 51 | console.error("Missing required environment variables"); 52 | console.error( 53 | "Required variables: APPLE_TEAM_ID, APPLE_KEY_ID, APPLE_CLIENT_ID, APPLE_PRIVATE_KEY_PATH" 54 | ); 55 | process.exit(1); 56 | } 57 | 58 | console.log("Attempting to read private key from:", PRIVATE_KEY_PATH); 59 | 60 | try { 61 | // Read the Apple private key (.p8 file) 62 | // This key should be downloaded from Apple Developer Console 63 | const privateKey = fs.readFileSync(path.resolve(PRIVATE_KEY_PATH)); 64 | 65 | // Configure the JWT payload according to Apple's specifications 66 | // See: https://developer.apple.com/documentation/sign_in_with_apple/generate_and_validate_tokens 67 | const payload = { 68 | iss: TEAM_ID, // Team ID from Apple Developer account 69 | iat: Math.floor(Date.now() / 1000), // Current timestamp 70 | exp: Math.floor(Date.now() / 1000) + 15777000, // 6 months expiry 71 | aud: "https://appleid.apple.com", // Required audience 72 | sub: CLIENT_ID, // Your app's identifier 73 | }; 74 | 75 | // Generate the client secret 76 | // Uses ES256 algorithm as required by Apple 77 | const clientSecret = sign(payload, privateKey, { 78 | algorithm: "ES256", 79 | keyid: KEY_ID, 80 | }); 81 | 82 | // Output the generated secret 83 | // This value should be used in your auth.ts configuration 84 | console.log("\nApple Client Secret:"); 85 | console.log(clientSecret); 86 | } catch (error: any) { 87 | console.error("Error reading private key:", error.message); 88 | process.exit(1); 89 | } 90 | -------------------------------------------------------------------------------- /basic-form/form.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { useState } from "react"; 4 | 5 | export default function Form() { 6 | const [state, setState] = useState({ 7 | firstName: "", 8 | lastName: "", 9 | email: "", 10 | message: "", 11 | }); 12 | 13 | const handleSubmit = (e: React.FormEvent) => { 14 | e.preventDefault(); 15 | console.log(state); 16 | 17 | alert("Form submitted"); 18 | }; 19 | 20 | return ( 21 |
22 |
23 |
24 |
25 | 30 | setState({ 31 | ...state, 32 | firstName: e.target.value, 33 | }) 34 | } 35 | /> 36 | 37 | 42 | setState({ ...state, lastName: e.target.value }) 43 | } 44 | /> 45 |
46 | 47 | 52 | setState({ ...state, email: e.target.value }) 53 | } 54 | /> 55 | 56 |