docs/self-hosting/auth/providers/apple.mdx
<Callout type={'warning'}> Apple Sign In requires a paid Apple Developer account ($99/year) and does not support localhost. You must use a domain with HTTPS for both development and production. </Callout>
<Steps> ### Create an App IDLobeHubcom.yourcompany.lobechatLobeHub Webcom.yourcompany.lobechat.web (this is your Client ID)your-domain.comhttps://your-domain.com/api/auth/callback/apple<Callout type={'info'}> Callback URL format:
- Production: `https://your-domain.com/api/auth/callback/apple`
- Apple does **not** support localhost or HTTP URLs
.p8) - you can only download it onceApple requires a JWT as the client secret. Generate it using your .p8 key file:
// Example using Node.js
const jwt = require('jsonwebtoken');
const fs = require('fs');
const privateKey = fs.readFileSync('AuthKey_XXXXX.p8');
const token = jwt.sign({}, privateKey, {
algorithm: 'ES256',
expiresIn: '180d', // Max 6 months
issuer: 'YOUR_TEAM_ID',
audience: 'https://appleid.apple.com',
subject: 'YOUR_SERVICES_ID', // Client ID
keyid: 'YOUR_KEY_ID',
});
<Callout type={'warning'}> The JWT expires after maximum 180 days. You need to regenerate and update it before expiration. </Callout>
| Environment Variable | Type | Description |
|---|---|---|
AUTH_SECRET | Required | Session encryption key, generate with openssl rand -base64 32 |
AUTH_SSO_PROVIDERS | Required | Set to apple |
AUTH_APPLE_CLIENT_ID | Required | Your Services ID |
AUTH_APPLE_CLIENT_SECRET | Required | The generated JWT |
AUTH_APPLE_APP_BUNDLE_IDENTIFIER | Optional | App Bundle ID (for native app integration) |
<Callout type={'tip'}> Go to 📘 Environment Variables for detailed information. </Callout> </Steps>
<Callout type={'info'}> After successful deployment, users will be able to authenticate with Apple and use LobeHub. </Callout>
Apple Sign In does not support localhost or non-HTTPS URLs. For local development, use a tunneling service like ngrok or deploy to a staging environment with HTTPS.
The JWT client secret expires after 180 days maximum. Set a reminder to regenerate it before expiration.