Rork で作ったアプリに Google サインインを実装して、いざ App Store に出そうとしたら「Guideline 4.8 — Login Services」でリジェクトされた、という相談をよく受けます。Apple が定めるルールはシンプルで、サードパーティのサインイン手段(Google, Facebook, LINE, X など)を1つでも提供するなら、Sign in with Apple も同等のオプションとして用意しなければなりません。
ここではRork のプロジェクトに Sign in with Apple を後付けする実装を、実際に審査を通った手順に沿って書いていきます。ドキュメントに沿って書いた通りに動かない箇所や、iOS シミュレータでは再現しない本番特有の挙動も含めて、つまずきやすいポイントを先回りで共有します。
なぜこのタイミングで実装しておくべきか
Sign in with Apple は「Apple がリジェクトしたから慌てて入れる」という順序で実装されがちですが、これは後手に回る典型例です。後から入れようとすると、既存のユーザー管理テーブルの設計を変える必要が出てきたり、Apple 固有の仕様(メール匿名化・初回サインインのみ氏名が返る、など)に合わせてバックエンドを書き直すことになります。
私自身も過去に2つのアプリで同じ失敗をしています。SNS ログインを実装した直後のリリースで必ず 4.8 リジェクトを受け、リリースが1週間遅れました。その経験から、現在は新規プロジェクトでは「他のサインイン手段を実装する前に Apple を先に入れる」ようにしています。Rork で生成したコードベースはまだ小さいうちに Apple を足しておくほうが、確実に楽です。
実装が必要になる条件
以下のいずれかに該当する場合、Sign in with Apple は実質必須です。
- Google / Facebook / X / LINE / Microsoft などサードパーティ認証を1つ以上使っている
- 独自のメール+パスワード認証だけなら免除されるケースがある(ただしメール必須で、Apple ユーザーには使いづらい)
- メールマジックリンクのみの場合も実質免除されるが、UX 上不利
逆に、認証自体をしないアプリ(ゲーム、ユーティリティ、閲覧専用など)はそもそも対象外です。
Expo ベースの Rork プロジェクトで準備すること
Rork で生成される典型的な構成は Expo SDK + React Native です。Sign in with Apple は expo-apple-authentication を使います。
# Rork エディタのターミナル、またはローカルで実行
npx expo install expo-apple-authenticationインストール後、app.json に iOS 専用の設定を追加します。Rork は自動で app.json を生成しますが、認証系は手動で追記が必要です。
{
"expo": {
"ios": {
"bundleIdentifier": "com.yourcompany.yourapp",
"usesAppleSignIn": true
},
"plugins": ["expo-apple-authentication"]
}
}usesAppleSignIn: true と plugins に expo-apple-authentication を両方入れるのがポイントです。どちらか片方だけだと、EAS Build で Entitlement が付与されず、ビルドは通るのに起動時にクラッシュするという分かりにくい失敗をします。
Apple Developer 側の設定
Apple Developer Portal で以下を有効化します。
- Certificates, Identifiers & Profiles → Identifiers から対象の App ID を開く
- 「Sign In with Apple」の Capability にチェックを入れる
- 保存後、Provisioning Profile を再生成する(ここを忘れがち)
再生成した Provisioning Profile を EAS に同期させるには、一度 eas build:configure を実行するか、次回のビルド前に eas credentials で最新状態にすると確実です。
最小実装:サインインボタンとハンドラ
Rork で生成された画面に、以下のコンポーネントを追加します。Apple は「Sign in with Apple」ボタンのデザインにも厳格で、提供されている純正コンポーネントをそのまま使うのが一番安全です。
import * as AppleAuthentication from 'expo-apple-authentication';
import { Platform, View, Alert } from 'react-native';
import { useEffect, useState } from 'react';
export function AppleSignInButton({ onSuccess }: { onSuccess: (user: AppleUser) => void }) {
const [available, setAvailable] = useState(false);
useEffect(() => {
// iOS 13+ のみサポート。iPad シミュレータでは動作するが実機確認を推奨
AppleAuthentication.isAvailableAsync().then(setAvailable);
}, []);
// Android / Web では表示しない(後述のフォールバックで対応)
if (Platform.OS !== 'ios' || !available) return null;
return (
<AppleAuthentication.AppleAuthenticationButton
buttonType={AppleAuthentication.AppleAuthenticationButtonType.SIGN_IN}
buttonStyle={AppleAuthentication.AppleAuthenticationButtonStyle.BLACK}
cornerRadius={8}
style={{ width: '100%', height: 48 }}
onPress={async () => {
try {
const credential = await AppleAuthentication.signInAsync({
requestedScopes: [
AppleAuthentication.AppleAuthenticationScope.FULL_NAME,
AppleAuthentication.AppleAuthenticationScope.EMAIL,
],
});
// credential.identityToken をサーバへ送り検証する
onSuccess({
user: credential.user,
email: credential.email, // 初回サインイン時のみ入る
fullName: credential.fullName, // 初回サインイン時のみ入る
identityToken: credential.identityToken!,
});
} catch (e: any) {
if (e.code === 'ERR_REQUEST_CANCELED') return;
Alert.alert('サインインに失敗しました', e.message);
}
}}
/>
);
}
type AppleUser = {
user: string;
email: string | null;
fullName: AppleAuthentication.AppleAuthenticationFullName | null;
identityToken: string;
};このコードで押さえておきたいのは、email と fullName が 初回サインイン時にしか返ってこない という Apple 固有の仕様です。2回目以降は null になるため、バックエンド側で初回に受け取った値を保存しておかないと、以後ユーザー名を表示できません。ここは他のソーシャルログインと最も挙動が違う部分で、実装を見直すポイントになります。
期待される出力
初回成功時、credential.user には 001234.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.xxxx のような Apple 固有のユーザー ID が返ります。この ID はアプリとユーザーの組み合わせで一意に発番され、アプリをアンインストールしても変わりません。バックエンド側ではこの user ID を主キーに紐付けて保存します。
バックエンド検証:identityToken を捨てない
よくある実装ミスが「identityToken を使わずに credential.user だけで認証する」というものです。これだと悪意あるクライアントが任意のユーザー ID を偽装して送れるため、サーバ側での認証としては成立しません。正しくは、受け取った identityToken を Apple の公開鍵で検証します。
// Node.js / Cloudflare Workers でも動く一般的な検証コード
import { createRemoteJWKSet, jwtVerify } from 'jose';
const JWKS = createRemoteJWKSet(new URL('https://appleid.apple.com/auth/keys'));
export async function verifyAppleIdentityToken(identityToken: string, audience: string) {
const { payload } = await jwtVerify(identityToken, JWKS, {
issuer: 'https://appleid.apple.com',
audience, // アプリの Bundle ID。Services ID を使う場合はそちらを指定
});
return {
sub: payload.sub as string, // = credential.user
email: payload.email as string | undefined,
emailVerified: payload.email_verified === 'true',
};
}audience には Bundle ID(例: com.yourcompany.yourapp)を入れます。Services ID(Web ログイン用)を使う場合はそちらを指定します。ここを間違えると JWTClaimValidationFailed でサーバ側だけ延々エラーが出る、という現象になります。
Android・Web ユーザーへの対応
Sign in with Apple はネイティブ UI としては iOS 限定ですが、Apple は「iOS 以外のプラットフォームでも同等のサインイン手段を提供すること」を求めています。Android / Web 版を出している場合は、Apple の OAuth フローをブラウザ経由で呼び出す必要があります。
Rork で Android ビルドや Web 版を出すなら、expo-auth-session を使って Apple の OAuth エンドポイント(Services ID 経由)に誘導するのが現実的です。ここは本記事の範囲を超えるため、Rork で iOS 実機テストを行う Rork Companion ガイド や App Store 提出の完全ガイド と併せて、別途 Services ID の準備手順を確認してください。
審査でつまずきやすい3つのポイント
実装できたと思っても、審査で指摘されやすいのは以下の3つです。
1. ボタンが他のサインインより下にある
Apple のガイドラインでは、Sign in with Apple を他の認証オプションより 上に、または同等に 配置することが推奨されています。Google ボタンだけ強調されていると、4.8 で指摘されることがあります。ボタンのサイズ・色のコントラストも揃えましょう。
2. メール共有オプションの説明不足
Apple はユーザーに「メールを共有する/隠す」を選ばせます。「隠す」を選ぶと @privaterelay.appleid.com の匿名メールがアプリに届きます。この匿名メールに送信したメールは Apple 経由でユーザーに転送される仕組みですが、これをテストせずに「この宛先は無効なユーザー」として除外する実装にしていると、匿名メールユーザーからの問い合わせに気づけません。
3. Apple ID 削除リクエストへの対応未実装
2022年6月以降、Sign in with Apple を使うアプリには「アカウント削除機能」の実装が義務付けられています。サインイン機能だけ入れて削除機能がないと、4.8 ではなく 5.1.1(v) で指摘されます。アプリ内に「アカウントを削除する」ボタンを設け、削除処理の際は AppleAuthentication.revokeAsync を呼び出して、Apple 側のトークンも失効させる必要があります。
料金プランと実機テストの組み合わせ
Sign in with Apple の開発は Apple Developer Program(年間 $99)が必須です。ここは Rork の料金とは別枠です。Rork 側のプラン選びについては Rork 料金プラン正直比較 2026 年版 にまとめてありますので、Apple Developer との組み合わせで最低限かかる費用を見積もるときに参考にしてください。
次のステップ
この記事のコードは最小構成ですが、これだけで iOS ビルド → TestFlight → 審査までの流れに乗せられます。次に取り組むなら、まずはシミュレータではなく実機で Apple ID サインインを試してみてください。匿名メールの動作や、同じ Apple ID でアンインストール→再インストールした時の挙動は、実機でないと再現しないものが多くあります。より本格的な課金連携まで踏み込むなら、Rork での Stripe サブスクリプション実装ガイド に進むとスムーズです。