KeyloomKeyloom
Keyloom Auth is currently in beta. Feedback and contributions are welcome!
Providers

Apple Provider

Configure Sign in with Apple for Keyloom. Complete Apple Developer setup, certificates, team ID, private keys, and troubleshooting.

Apple Provider

Add Sign in with Apple to your Keyloom app. This guide covers the complete Apple Developer setup process including certificates and private keys.

Prerequisites

  • Apple Developer account (individual or organization)
  • Keyloom app with @keyloom/providers installed
  • Public app URL for callback configuration
  • OpenSSL or similar tool for certificate handling

Apple Developer setup

1. Create App ID

  1. Go to Apple Developer Console
  2. Navigate to Certificates, Identifiers & Profiles → Identifiers
  3. Click "+" to create new App ID
  4. Select "App IDs" and continue
  5. Configure:
    • Description: Your app name
    • Bundle ID: com.yourcompany.yourapp (explicit, not wildcard)
    • Capabilities: Enable "Sign In with Apple"

2. Create Services ID

  1. In Identifiers, click "+" again
  2. Select "Services IDs" and continue
  3. Configure:
    • Description: Your app name (web)
    • Identifier: com.yourcompany.yourapp.web (different from App ID)
  4. Enable "Sign In with Apple"
  5. Click "Configure" next to Sign In with Apple:
    • Primary App ID: Select the App ID created above
    • Web Domain: yourapp.com (your domain, no protocol)
    • Return URLs: https://yourapp.com/api/auth/oauth/apple/callback

3. Create Private Key

  1. Navigate to Keys section
  2. Click "+" to create new key
  3. Configure:
    • Key Name: "Sign in with Apple Key"
    • Services: Enable "Sign In with Apple"
  4. Click "Configure" and select your Primary App ID
  5. Register the key and download the .p8 file
  6. Note the Key ID (10-character string)

4. Get Team ID

  1. In Apple Developer Console, go to Membership
  2. Note your Team ID (10-character string)

Environment variables

.env.local
APPLE_CLIENT_ID=com.yourcompany.yourapp.web
APPLE_TEAM_ID=ABC123DEF4
APPLE_KEY_ID=XYZ987WVU6
APPLE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----
MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQg...
-----END PRIVATE KEY-----"
NEXT_PUBLIC_APP_URL=https://yourapp.com

Private key handling

# Convert .p8 file to single-line format
cat AuthKey_XYZ987WVU6.p8 | tr '\n' '\\n'

Add to .env.local:

APPLE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\\nMIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQg...\\n-----END PRIVATE KEY-----"

Option 2: File path

.env.local
APPLE_PRIVATE_KEY_PATH=./keys/AuthKey_XYZ987WVU6.p8

Provider configuration

keyloom.config.ts
import { defineKeyloom } from "@keyloom/core";
import { apple } from "@keyloom/providers";

export default defineKeyloom({
  baseUrl: process.env.NEXT_PUBLIC_APP_URL!,
  providers: [
    apple({
      clientId: process.env.APPLE_CLIENT_ID!,
      teamId: process.env.APPLE_TEAM_ID!,
      keyId: process.env.APPLE_KEY_ID!,
      privateKey: process.env.APPLE_PRIVATE_KEY!,
      // Optional: customize scopes
      scope: "name email",
    }),
  ],
  // ... rest of config
});

Sign-in UI example

components/SignIn.tsx
export function SignInWithApple() {
  return (
    <a
      href="/api/auth/oauth/apple/start?callbackUrl=/dashboard"
      className="flex items-center gap-2 px-4 py-2 bg-black text-white rounded"
    >
      <AppleIcon />
      Continue with Apple
    </a>
  );
}

User profile mapping

Apple returns profile data in the ID token:

{
  "sub": "001234.567890abcdef123456789",
  "email": "user@privaterelay.appleid.com",
  "email_verified": "true",
  "name": {
    "firstName": "John",
    "lastName": "Doe"
  }
}

Keyloom maps it to:

{
  id: profile.sub,
  email: profile.email,
  name: profile.name ? `${profile.name.firstName} ${profile.name.lastName}` : null,
  image: null, // Apple doesn't provide profile images
  emailVerified: profile.email_verified === "true",
}

Callback URL patterns

  • Development: http://localhost:3000/api/auth/oauth/apple/callback
  • Production: https://yourapp.com/api/auth/oauth/apple/callback
  • Must match exactly what's configured in Apple Developer Console

Error handling

Common Apple OAuth errors:

  • invalid_client: Client ID, team ID, or key ID mismatch
  • invalid_grant: Authorization code expired or invalid
  • invalid_request: Missing required parameters
  • unsupported_response_type: Incorrect response type
Error handling example
// In your error boundary or callback handler
if (error?.code === "oauth_error" && error?.provider === "apple") {
  switch (error?.details?.error) {
    case "invalid_client":
      return "Apple configuration error. Check client ID, team ID, and key ID.";
    case "invalid_grant":
      return "Authorization expired. Please try signing in again.";
    default:
      return "Apple sign-in failed. Please try again.";
  }
}

Security considerations

  • Private Key: Store securely; never commit to version control
  • Team ID/Key ID: Can be public but keep organized
  • Client Secret: Generated dynamically using private key (handled by Keyloom)
  • Email Privacy: Users may choose private relay emails

Apple-specific features

  • Private Email Relay: Users can hide their real email
  • Name Sharing: Users can choose to share or hide their name
  • Two-Factor Authentication: Built into Apple ID
  • Cross-Platform: Works on iOS, macOS, web

Troubleshooting

Invalid client error

  • Verify Client ID matches Services ID identifier
  • Check Team ID is correct (10 characters)
  • Ensure Key ID matches the downloaded key

Private key issues

  • Verify .p8 file format and line endings
  • Check private key is properly escaped in environment variable
  • Ensure key has "Sign In with Apple" capability enabled

Callback URL mismatch

  • Must exactly match what's configured in Apple Developer Console
  • Check protocol (HTTP vs HTTPS), domain, and path
  • Verify domain is added to Web Domain list

Missing user data

  • Apple only provides name/email on first authorization
  • Subsequent sign-ins may only include user ID
  • Store user data on first sign-in for future reference

Performance considerations

  • Apple OAuth is reliable but can be slower than other providers
  • Client secret generation adds minimal overhead
  • Cache user profile data after first sign-in

See also

Next steps

  • Test the complete sign-in flow in development
  • Configure production Apple Developer settings
  • Handle private email relay addresses in your app logic

How is this guide?