Apple Authentication
This guide explains how to set up Sign in with Apple for the Zero Kelvin application.
Prerequisites
- An Apple Developer account ($99/year)
- Access to the Apple Developer Portal
Step 1: Create an App ID
- Go to the Apple Developer Portal
- Navigate to Certificates, Identifiers & Profiles
- Select Identifiers from the sidebar
- Click the + button to create a new identifier
- Select App IDs and click Continue
- Select App as the type and click Continue
- Fill in the details:
- Description: Zero Kelvin
- Bundle ID: Choose Explicit and enter
com.example.web
- Scroll down to Capabilities and check Sign in with Apple
- Click Continue and then Register
Step 2: Create a Services ID
- In the Identifiers section, click the + button again
- Select Services IDs and click Continue
- Fill in the details:
- Description: Zero Kelvin Web
- Identifier:
com.example.web.signin(this will be yourAUTH_APPLE_ID)
- Click Continue and then Register
- Click on the newly created Services ID
- Check Sign in with Apple and click Configure
- Select your App ID as the Primary App ID
- Under Domains and Subdomains, add:
localhost(for development)- Your production domain (e.g.,
example.com)
- Under Return URLs, add:
http://localhost:3000/api/auth/callback/apple(for development)- Your production callback URL (e.g.,
https://example.com/api/auth/callback/apple)
- Click Save and then Continue and Save
Step 3: Create a Private Key
- Navigate to Keys in the sidebar
- Click the + button to create a new key
- Enter a Key Name (e.g., "Zero Kelvin Sign in with Apple")
- Check Sign in with Apple and click Configure
- Select your App ID as the Primary App ID
- Click Save and then Continue
- Click Register
- Important: Download the key file (
.p8) immediately - you can only download it once! - Note the Key ID displayed on the page
Step 4: Generate the Client Secret
Apple uses a JWT as the client secret. You need to generate this from your private key.
Option 1: Generate at Build Time
Create a script to generate the secret:
// scripts/generate-apple-secret.js
const jwt = require("jsonwebtoken");
const fs = require("fs");
const privateKey = fs.readFileSync("path/to/AuthKey_XXXXXXXX.p8");
const teamId = "YOUR_TEAM_ID"; // Found in Apple Developer account
const clientId = "com.example.web.signin"; // Your Services ID
const keyId = "YOUR_KEY_ID"; // From step 3
const token = jwt.sign({}, privateKey, {
algorithm: "ES256",
expiresIn: "180d",
audience: "https://appleid.apple.com",
issuer: teamId,
subject: clientId,
keyid: keyId,
});
console.log(token);
Option 2: Use Environment Variables
Store the private key content in an environment variable and generate the secret dynamically in auth.ts:
import Apple from "next-auth/providers/apple"
import jwt from "jsonwebtoken"
function getAppleSecret() {
const privateKey = process.env.AUTH_APPLE_PRIVATE_KEY?.replace(/\\n/g, '\n')
return jwt.sign({}, privateKey, {
algorithm: 'ES256',
expiresIn: '180d',
audience: 'https://appleid.apple.com',
issuer: process.env.AUTH_APPLE_TEAM_ID,
subject: process.env.AUTH_APPLE_ID,
keyid: process.env.AUTH_APPLE_KEY_ID,
})
}
// In your providers array:
Apple({
clientId: process.env.AUTH_APPLE_ID,
clientSecret: getAppleSecret(),
}),
Step 5: Configure Environment Variables
Add the following to your .env.local file:
AUTH_APPLE_ID="com.example.web.signin"
AUTH_APPLE_SECRET="your-generated-jwt-secret"
# Or if generating dynamically:
AUTH_APPLE_TEAM_ID="YOUR_TEAM_ID"
AUTH_APPLE_KEY_ID="YOUR_KEY_ID"
AUTH_APPLE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"
Step 6: Test the Integration
- Start the development server:
nx dev web
- Navigate to
http://localhost:3000 - Click the Sign In button
- Select Continue with Apple
Important Notes
Email Privacy
- Apple offers users the option to hide their email address
- If the user chooses "Hide My Email", Apple provides a private relay email
- Store both the Apple-provided email and any private relay addresses
Client Secret Expiration
- The JWT client secret expires after 180 days (maximum)
- Set up a process to regenerate the secret before expiration
HTTPS Required
- Apple Sign In requires HTTPS in production
- Development with
localhostis allowed as an exception
Troubleshooting
"invalid_client"
- Verify your Services ID matches
AUTH_APPLE_ID - Check that the JWT secret is valid and not expired
- Ensure the redirect URI matches exactly
"redirect_uri_mismatch"
- The return URL must exactly match what's configured in the Services ID
- Check for trailing slashes and protocol (http vs https)
User email not returned
- Apple only returns the email on the first authentication
- Store the user's email in your database on first sign-in