
Apple
Run a local Sign in with Apple OIDC emulator so you can develop and test Apple OAuth flows without calling Apple’s production APIs.
Install
npx skills add https://github.com/vercel-labs/emulate --skill appleWhat is this skill?
- Authorization code flow with PKCE and RS256 ID tokens plus OIDC discovery at a local base URL
- Maps real appleid.apple.com endpoints to emulator paths via APPLE_EMULATOR_URL
- CLI start with npx emulate --service apple (default http://localhost:4000) or createEmulator in TypeScript
- Supports programmatic port selection and curl-based token exchange during local auth debugging
Adoption & trust: 72 installs on skills.sh; 1.3k GitHub stars; 2/3 security scanners passed (skills.sh audits).
Recommended Skills
Entra App Registrationmicrosoft/azure-skills
Azure Aigatewaymicrosoft/azure-skills
Lark Openapi Explorerlarksuite/cli
Supabasesupabase/agent-skills
Firebase Auth Basicsfirebase/agent-skills
Firebase Data Connectfirebase/agent-skills
Journey fit
Common Questions / FAQ
Is Apple safe to install?
skills.sh reports 2 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.
SKILL.md
READMESKILL.md - Apple
# Apple Sign In Emulator Sign in with Apple emulation with authorization code flow, PKCE support, RS256 ID tokens, and OIDC discovery. ## Start ```bash # Apple only npx emulate --service apple # Default port (when run alone) # http://localhost:4000 ``` Or programmatically: ```typescript import { createEmulator } from 'emulate' const apple = await createEmulator({ service: 'apple', port: 4004 }) // apple.url === 'http://localhost:4004' ``` ## Pointing Your App at the Emulator ### Environment Variable ```bash APPLE_EMULATOR_URL=http://localhost:4004 ``` ### OAuth URL Mapping | Real Apple URL | Emulator URL | |----------------|-------------| | `https://appleid.apple.com/.well-known/openid-configuration` | `$APPLE_EMULATOR_URL/.well-known/openid-configuration` | | `https://appleid.apple.com/auth/authorize` | `$APPLE_EMULATOR_URL/auth/authorize` | | `https://appleid.apple.com/auth/token` | `$APPLE_EMULATOR_URL/auth/token` | | `https://appleid.apple.com/auth/keys` | `$APPLE_EMULATOR_URL/auth/keys` | | `https://appleid.apple.com/auth/revoke` | `$APPLE_EMULATOR_URL/auth/revoke` | ### Auth.js / NextAuth.js ```typescript import Apple from '@auth/core/providers/apple' Apple({ clientId: process.env.APPLE_CLIENT_ID, clientSecret: process.env.APPLE_CLIENT_SECRET, authorization: { url: `${process.env.APPLE_EMULATOR_URL}/auth/authorize`, params: { scope: 'openid email name', response_mode: 'form_post' }, }, token: { url: `${process.env.APPLE_EMULATOR_URL}/auth/token`, }, jwks_endpoint: `${process.env.APPLE_EMULATOR_URL}/auth/keys`, }) ``` ### Passport.js ```typescript import { Strategy as AppleStrategy } from 'passport-apple' const APPLE_URL = process.env.APPLE_EMULATOR_URL ?? 'https://appleid.apple.com' new AppleStrategy({ clientID: process.env.APPLE_CLIENT_ID, teamID: process.env.APPLE_TEAM_ID, keyID: process.env.APPLE_KEY_ID, callbackURL: 'http://localhost:3000/api/auth/callback/apple', authorizationURL: `${APPLE_URL}/auth/authorize`, tokenURL: `${APPLE_URL}/auth/token`, }, verifyCallback) ``` ## Seed Config ```yaml apple: users: - email: testuser@icloud.com name: Test User given_name: Test family_name: User - email: private@example.com name: Private User is_private_email: true oauth_clients: - client_id: com.example.app team_id: TEAM001 name: My Apple App redirect_uris: - http://localhost:3000/api/auth/callback/apple ``` When no OAuth clients are configured, the emulator accepts any `client_id`. With clients configured, strict validation is enforced for `client_id` and `redirect_uri`. Users with `is_private_email: true` get a generated `@privaterelay.appleid.com` email in the `id_token` instead of their real email. ## API Endpoints ### OIDC Discovery ```bash curl http://localhost:4004/.well-known/openid-configuration ``` Returns the standard OIDC discovery document with all endpoints pointing to the emulator: ```json { "issuer": "http://localhost:4004", "authorization_endpoint": "http://localhost:4004/auth/authorize", "token_endpoint": "http://localhost:4004/auth/token", "jwks_uri": "http://localhost:4004/auth/keys", "revocation_endpoint": "http://localhost:4004/auth/revoke", "response_types_supported": ["code"], "subject_types_supported": ["pairwise"], "id_token_signing_alg_values_supported": ["RS256"], "scope