apple について
apple は、Sign in with Apple 連携をテストする開発者向けの認証エミュレーターです。認可コードフロー、PKCE、RS256 ID トークン、OIDC ディスカバリーに対応しています。
主な機能
- 01認可コードフロー
- 02PKCE 対応
- 03RS256 ID トークンの発行
- 04OIDC ディスカバリーと JWKS
- 05トークンの更新と失効
活用シーン
- 01Apple サインインのコールバックテスト
- 02PKCE 認可コード交換の検証
- 03ID トークン署名検証のテスト
- 04プライベートリレーのメール動作確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ vercel-labs/ emulate --skill appleインストール後、Claude Code で/appleを入力して読み込まれたか確認します。
詳細
Apple Sign In Emulator
認証コードフロー、PKCE サポート、RS256 ID トークン、OIDC ディスカバリーに対応した「Apple でサインイン」のエミュレーションです。
起動
ローカルのリスナーは、デフォルトで 127.0.0.1 にバインドされます。コンテナーやほかのマシンからアクセスするには、CLI に --host 0.0.0.0、または createEmulator に hostname: '0.0.0.0' を渡してください。クライアントから到達可能な URL を通知するには、--base-url または baseUrl を設定します。
# Apple only
npx emulate --service apple
# Default port (when run alone)
# http://localhost:4000
または、プログラムから起動できます。
import { createEmulator } from 'emulate'
const apple = await createEmulator({ service: 'apple', port: 4004 })
// apple.url === 'http://localhost:4004'
アプリの接続先をエミュレーターに設定する
環境変数
APPLE_EMULATOR_URL=http://localhost:4004
OAuth URL のマッピング
| 実際の Apple URL | エミュレーター 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
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
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)
シード設定
apple:
users:
- email: [email protected]
name: Test User
given_name: Test
family_name: User
- email: [email protected]
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
OAuth クライアントが設定されていない場合、エミュレーターは任意の client_id を受け入れます。クライアントが設定されている場合は、client_id と redirect_uri が厳密に検証されます。
is_private_email: true のユーザーには、実際のメールアドレスの代わりに、id_token 内で生成された @privaterelay.appleid.com のメールアドレスが割り当てられます。
API エンドポイント
OIDC ディスカバリー
curl http://localhost:4004/.well-known/openid-configuration
すべてのエンドポイントがエミュレーターを指す、標準の OIDC ディスカバリードキュメントを返します。
{
"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"],
"scopes_supported": ["openid", "email", "name"],
"token_endpoint_auth_methods_supported": ["client_secret_post"],
"response_modes_supported": ["query", "fragment", "form_post"]
}
JWKS
curl http://localhost:4004/auth/keys
id_token の署名を検証するための RSA 公開鍵(kid: emulate-apple-1)を返します。
認証
# Browser flow: redirects to a user picker page
curl -v "http://localhost:4004/auth/authorize?\
client_id=com.example.app&\
redirect_uri=http://localhost:3000/api/auth/callback/apple&\
scope=openid+email+name&\
response_type=code&\
state=random-state&\
nonce=random-nonce&\
response_mode=form_post"
クエリパラメーター:
| パラメーター | 説明 |
|---|---|
client_id | OAuth クライアント ID(Apple Services ID) |
redirect_uri | コールバック URL |
scope | スペース区切りのスコープ(openid email name) |
state | CSRF 保護用の不透明な state |
nonce | ID トークン用の nonce(任意) |
response_mode | query(デフォルト)、form_post、または fragment |
エミュレーターは、シード済みのユーザーを選択する HTML ページを表示します。選択後、code と state を付けて redirect_uri にリダイレクトします(form_post の場合はフォームを自動送信します)。ユーザーとクライアントの組み合わせごとに初回の認証では、user の JSON データも含まれます(Apple の実際の動作と同じです)。
トークン交換
curl -X POST http://localhost:4004/auth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "code=<authorization_code>&\
client_id=com.example.app&\
client_secret=<client_secret>&\
grant_type=authorization_code"
以下を返します。
{
"access_token": "apple_...",
"refresh_token": "r_apple_...",
"id_token": "<jwt>",
"token_type": "Bearer",
"expires_in": 3600
}
id_token は、sub、email、email_verified(文字列)、is_private_email(文字列)、real_user_status、auth_time、および任意の nonce を含む RS256 JWT です。
リフレッシュトークン
curl -X POST http://localhost:4004/auth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "refresh_token=r_apple_...&\
client_id=com.example.app&\
grant_type=refresh_token"
新しい access_token と id_token を返します。リフレッシュ時に新しい refresh_token は発行されません(Apple の動作と同じです)。
トークンの取り消し
curl -X POST http://localhost:4004/auth/revoke \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "token=apple_..."
200 OK を返します。トークンはエミュレーターのトークンマップから削除されます。
よくあるパターン
認証コードフロー全体
APPLE_URL="http://localhost:4004"
CLIENT_ID="com.example.app"
REDIRECT_URI="http://localhost:3000/api/auth/callback/apple"
# 1. Open in browser (user picks a seeded account)
# $APPLE_URL/auth/authorize?client_id=$CLIENT_ID&redirect_uri=$REDIRECT_URI&scope=openid+email+name&response_type=code&state=abc&response_mode=form_post
# 2. After user selection, emulator posts to:
# $REDIRECT_URI with code=<code>&state=abc (and user JSON on first auth)
# 3. Exchange code for tokens
curl -X POST $APPLE_URL/auth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "code=<code>&client_id=$CLIENT_ID&grant_type=authorization_code"
# 4. Decode the id_token JWT to get user info
プライベートリレーのメールアドレス
シード設定でユーザーの is_private_email: true が指定されている場合、id_token にはユーザーの実際のメールアドレスではなく、生成された @privaterelay.appleid.com のメールアドレスが含まれます。これは Apple の「メールを非公開」機能と同じ動作です。
組み込みエミュレーターと併用するカスタムエミュレーター
npx emulate init --custom inventory を使って、サードパーティ API エミュレーターをひな形から作成し、テストできます。emulate の defineConfig を使って emulate.config.ts に登録し、{ emulator: "apple" } などの組み込みエントリーと併用します。npx emulate start --watch を実行すると、インポートを再読み込みし、表示された /_emulate URL でカスタムの状態を確認できます。再読み込みが成功すると、実行状態はシードにリセットされます。既存のフラットなシード設定も引き続き使用できます。--config で明示的なファイルを選択できます。サードパーティ API エミュレーターの作成とテストについては、https://emulate.dev/docs/custom-emulators を参照してください。