本文へスキップ
Unveilydocs

ソーシャルログインのセットアップ

Google・Apple のソーシャルログインをすばやく設定します。

ひと目でわかる

Unveily SDK はプランによってソーシャルログインで使えるプロバイダーが異なります。

ソーシャルBasicStandardPro
Google
Apple(iOS)
Apple(Android)
Kakao
Naver
LINE
Meta

Google と Apple はどちらも Firebase Auth を通じて処理されます — カスタムバックエンドは不要です。

両プロバイダーとも Firebase Console で設定し、同一の google-services.json が両方に適用されます。 SDK は Google および Apple ログイン時に Firebase ID TokenidToken)を返します。 サーバー側では Firebase Admin SDK の verifyIdToken() で検証できます。

iOS のプロバイダー対応状況

現在 iOS では Apple と Google ログインのみが動作します。iOS で Kakao・Naver・LINE・Meta を呼び出すと、今後の iOS SDK アップデートまで SDK_NOT_READY エラーが返される場合があります。Android はすべてのプロバイダーに対応しています。Apple/Google は両プラットフォームで動作します。

また、iOS の Apple ログインは idToken に加えて authorizationCode(Apple 専用)を返します。上記の「Google + Apple は idToken を返す」という記述は Firebase 経路(Android および iOS の Firebase 処理分)を指します。


1. キー設定ファイル

assets/config/social_login_config.json に各ソーシャルの SDK キーを入力します。

{
  "kakao": {
    "nativeAppKey": "ここにKakaoネイティブアプリキーを入力"
  },
  "naver": {
    "clientId": "ここにNaverクライアントIDを入力",
    "clientSecret": "ここにNaverクライアントシークレットを入力",
    "appName": "アプリ名"
  },
  "line": {
    "channelId": "ここにLINEチャンネルIDを入力"
  },
  "meta": {
    "appId": "ここにMetaアプリIDを入力",
    "clientToken": "ここにMetaクライアントトークンを入力"
  }
}
  • キーが空の場合、そのソーシャルは自動的に無効になります。
  • Google・Apple: google-services.json + Firebase Console で設定します。このファイルへの追加項目は不要です。

2. build.gradle.kts のプレースホルダーを修正する

Kakao と Meta はディープリンクのコールバックのために、build.gradle.kts の manifest placeholder を更新する必要があります。

// app/build.gradle.kts — defaultConfig 内
defaultConfig {
    // Kakao: "kakao" + nativeAppKey
    manifestPlaceholders["kakaoScheme"] = "kakaoここにKakaoネイティブアプリキーを入力"
    // Meta: "fb" + appId
    manifestPlaceholders["facebookLoginProtocolScheme"] = "fbここにMetaアプリIDを入力"
}

3. ソーシャルボタンの表示制御

assets/config.jsonsocialLogin セクションでボタンの表示・非表示を切り替えます。

{
  "socialLogin": {
    "google": true,
    "apple": true,
    "kakao": true,
    "naver": true,
    "line": false,
    "meta": false
  }
}
  • true: ボタンを表示します(ただし、プランでも許可されている場合のみ動作します)
  • false: ボタンを非表示にします

4. 開発者コンソールへの登録手順

Google

  1. Firebase Console → プロジェクトを作成
  2. Authentication → ログイン方法 → Google を有効にする
  3. google-services.json をダウンロードして app/ フォルダーに置き換えます

Apple(iOS および Android)

iOS・Android どちらも Apple サインインは Firebase Auth を通じて処理されます — 同一の Firebase プロジェクトが両プラットフォームをカバーします。

  1. Apple Developer → Certificates, Identifiers & Profiles:
    • Services ID を作成(逆ドメイン形式、例: com.yourcompany.app
    • Sign In with Apple を有効にした Key を作成 → Team IDKey ID をメモし、.p8 キーをダウンロード
  2. Firebase Console → Authentication → ログイン方法 → Apple を有効にする
    • Team ID・Services ID・Key ID を入力し、.p8 秘密鍵の内容を貼り付けます
  3. 同一の google-services.json が Google と Apple の両方に適用されます — 追加ファイルは不要です。

Firebase が Apple の OAuth フロー全体(Android の Chrome カスタムタブを含む)を内部で処理します。 サーバー側のコールバックエンドポイントやカスタム URL スキームは不要です。

Kakao

  1. Kakao 開発者コンソール → マイアプリケーション → アプリケーションを追加
  2. アプリキー → ネイティブアプリキー をコピー
  3. プラットフォーム → Android → パッケージ名とマーケット URL を登録
  4. Kakao ログイン → 有効化 → 同意項目の設定(ニックネーム・メールなど)
  5. social_login_config.jsonkakao.nativeAppKey を入力
  6. build.gradle.ktsmanifestPlaceholders["kakaoScheme"] = "kakao{ネイティブアプリキー}" を修正
  1. Naver 開発者センター → Application → アプリケーションを登録
  2. 使用する API → ネアロ(Naver ID でログイン) を選択
  3. Android → パッケージ名を登録
  4. Client ID / Client Secret をコピー
  5. social_login_config.jsonnaver.clientIdnaver.clientSecretnaver.appName を入力

LINE

  1. LINE Developers → Providers → Create → Channel を作成
  2. Channel の種類 → LINE Login を選択
  3. Android Package Name を登録
  4. Channel ID をコピー
  5. social_login_config.jsonline.channelId を入力

Meta(Facebook)

  1. Meta for Developers → My Apps → Create App
  2. 製品を追加 → Facebook Login を選択
  3. 設定 → 基本設定 → アプリ IDクライアントトークン をコピー
  4. Android → パッケージ名とキーハッシュを登録
  5. social_login_config.jsonmeta.appIdmeta.clientToken を入力
  6. build.gradle.ktsmanifestPlaceholders["facebookLoginProtocolScheme"] = "fb{アプリID}" を修正

5. JS Bridge API

ログイン

window.unveilyBridge.auth.socialLogin({
  provider: 'google' // 'apple' | 'kakao' | 'naver' | 'line' | 'meta'
});

ログインのコールバック

ページに以下の関数を宣言しておくと、結果を受け取れます。

function onSocialLoginResult(result) {
  if (result.success) {
    console.log(result.provider);     // 'google' | 'apple' | 'kakao' | ...
    console.log(result.uid);          // Firebase UID(Google/Apple)またはソーシャルの固有 ID
    console.log(result.displayName);  // 名前(null の場合あり)
    console.log(result.email);        // メール(null の場合あり)
    console.log(result.profileImage); // プロフィール画像の URL(null の場合あり)
    console.log(result.idToken);      // Firebase ID Token(Google + Apple のみ。Kakao/Naver/LINE/Meta は null)
    // idToken を使って Firebase Admin SDK でサーバー側検証を行います
  } else {
    console.error(result.error);
    // 主なエラーコード:
    // FEATURE_NOT_ALLOWED  → プランが対応していない(result.requiredTier を含む)
    // PROVIDER_DISABLED    → config.json で false に設定されている
    // SDK_NOT_CONFIGURED   → social_login_config.json にキーが未入力
    // SDK_NOT_READY        → iOS で未対応のプロバイダー(Kakao/Naver/LINE/Meta)
    // LOGIN_CANCELLED      → ユーザーがログイン画面を閉じた
  }
}

ログアウト

window.unveilyBridge.auth.logout({ provider: 'google' });

連携解除(ソーシャルプロバイダーの切り離し)

該当のソーシャルプロバイダーとの連携のみを解除します。アカウント自体は削除されません。

window.unveilyBridge.auth.revoke({ provider: 'kakao' });

Google / Apple の連携解除

revoke は Firebase の user.unlink() を呼び出します — 該当プロバイダーの連携のみ解除されます。 Firebase アカウントはそのまま維持されます。 アカウント削除(退会)はサーバー側で user.delete() を呼び出す別途の処理が必要です。

ログアウト・連携解除のコールバック

function onSocialAuthResult(result) {
  // result.success  — true/false
  // result.action   — 'logout' | 'revoke'
  // result.provider — 'google' | 'apple' | 'kakao' | ...
  // result.error    — 失敗時のエラーコード
}

6. エラーコード参照

エラーコード説明
FEATURE_NOT_ALLOWED現在のプランで許可されていないソーシャル(requiredTier を含む)
PROVIDER_DISABLEDconfig.json でそのソーシャルが false になっている
SDK_NOT_CONFIGUREDsocial_login_config.json のキーが空
SDK_NOT_READYiOS でまだ対応していないプロバイダー(Kakao/Naver/LINE/Meta — 今後の iOS SDK アップデートで対応予定)
LOGIN_CANCELLEDユーザーがログイン画面を閉じた
UNKNOWN_PROVIDERサポートされていない provider の値
GOOGLE_ID_TOKEN_NULLGoogle ID トークンの発行失敗
FIREBASE_AUTH_FAILEDFirebase サインイン認証情報が拒否された
APPLE_NO_USERApple サインイン成功後、Firebase がユーザーを返さなかった
APPLE_ERRORApple サインイン失敗(一般)
GOOGLE_REVOKE_FAILEDGoogle プロバイダーの連携解除失敗
APPLE_REVOKE_FAILEDApple プロバイダーの連携解除失敗
NAVER_NO_TOKENNaver アクセストークンがない
LINE_INIT_FAILEDLINE SDK の初期化失敗

7. profileImage の処理ルール

ソーシャル提供有無
Googleほぼ常に提供(ない場合は null
Apple常に null(元から提供なし)
Kakao同意項目の設定時に提供
Naver同意項目の設定時に提供
LINEユーザーのプロフィール公開設定時に提供
Meta公開プロフィールの設定時に提供

null の場合は、お客様側でデフォルト画像を表示するように処理してください。

function onSocialLoginResult(result) {
  const avatar = result.profileImage
    ?? '/images/default-avatar.png';
  document.getElementById('avatar').src = avatar;
}

8. Apple の displayName キャッシュ

Apple は初回ログイン時のみユーザー名を提供します。SDK はこれをローカルにキャッシュします。

動作処理
初回ログイン(displayName あり)キャッシュに保存して渡す
再ログイン(displayName が null)キャッシュした値で代替して渡す
ログアウトキャッシュを保持(再ログインに備えて)
連携解除(revoke)キャッシュを削除(再連携時に Apple が新しく提供)
プラットフォームキャッシュ保存場所キーの形式
iOSUserDefaultsapple_name_{uid}
AndroidSharedPreferences("unveily_apple_name_cache")apple_name_{uid}

9. 完成例

// ログインボタンのクリック
document.getElementById('btn-google').addEventListener('click', () => {
  window.unveilyBridge.auth.socialLogin({ provider: 'google' });
});

// 結果の処理
function onSocialLoginResult(result) {
  if (!result.success) {
    if (result.error === 'FEATURE_NOT_ALLOWED') {
      alert(`${result.requiredTier} プラン以上でご利用いただけます。`);
    } else if (result.error !== 'LOGIN_CANCELLED') {
      alert('ログインに失敗しました。');
    }
    return;
  }

  // サーバーに送信 — Google/Apple は idToken でサーバー側検証を行います
  sendToServer(result);
}

async function sendToServer(result) {
  await fetch('/api/auth/social', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      provider: result.provider,
      uid:      result.uid,
      idToken:  result.idToken,   // Firebase ID Token(Google/Apple)— サーバー側検証用
      email:    result.email,
      displayName: result.displayName
    })
  });
}

サーバー側の Firebase ID Token 検証

Google および Apple ログインの場合、Firebase Admin SDK を使ってサーバー側で idToken を検証します。

// npm install firebase-admin
import admin from 'firebase-admin';
admin.initializeApp({ credential: admin.credential.applicationDefault() });

app.post('/api/auth/social', async (req, res) => {
  const { provider, uid, idToken, email, displayName } = req.body;

  // Google および Apple の Firebase ID Token を検証
  if (idToken) {
    const decoded = await admin.auth().verifyIdToken(idToken);
    if (decoded.uid !== uid) return res.status(401).json({ error: 'UID mismatch' });
  }

  // uid でユーザーを検索または作成
  let user = await db.users.findOne({ socialProvider: provider, socialId: uid });
  if (!user) {
    user = await db.users.create({ socialProvider: provider, socialId: uid, email, name: displayName });
  }

  req.session.userId = user.id;
  res.json({ ok: true, user: { id: user.id, name: user.name } });
});
// NuGet: FirebaseAdmin
using FirebaseAdmin;
using FirebaseAdmin.Auth;

[HttpPost("auth/social")]
public async Task<IActionResult> SocialLogin([FromBody] SocialLoginRequest request)
{
    // Google および Apple の Firebase ID Token を検証
    if (!string.IsNullOrEmpty(request.IdToken))
    {
        var decoded = await FirebaseAuth.DefaultInstance.VerifyIdTokenAsync(request.IdToken);
        if (decoded.Uid != request.Uid)
            return Unauthorized(new { error = "UID mismatch" });
    }

    var user = await _userService.FindOrCreateBySocialAsync(
        request.Provider, request.Uid, request.Email, request.DisplayName);

    HttpContext.Session.SetInt32("UserId", user.Id);
    return Ok(new { ok = true, user = new { user.Id, user.Name } });
}
// Maven: com.google.firebase:firebase-admin
@PostMapping("/api/auth/social")
public ResponseEntity<?> socialLogin(@RequestBody SocialLoginRequest request,
                                      HttpSession session) throws FirebaseAuthException {
    // Google および Apple の Firebase ID Token を検証
    if (request.getIdToken() != null) {
        FirebaseToken decoded = FirebaseAuth.getInstance().verifyIdToken(request.getIdToken());
        if (!decoded.getUid().equals(request.getUid()))
            return ResponseEntity.status(401).body(Map.of("error", "UID mismatch"));
    }

    User user = userService.findOrCreateBySocial(
        request.getProvider(), request.getUid(), request.getEmail(), request.getDisplayName());
    session.setAttribute("userId", user.getId());
    return ResponseEntity.ok(Map.of("ok", true, "userId", user.getId()));
}
<?php
// composer require kreait/firebase-php
use Kreait\Firebase\Factory;

$data = json_decode(file_get_contents('php://input'), true);
$provider    = $data['provider'];
$uid         = $data['uid'];
$idToken     = $data['idToken'] ?? null;
$email       = $data['email'] ?? null;
$displayName = $data['displayName'] ?? null;

// Google および Apple の Firebase ID Token を検証
if ($idToken) {
    $firebase = (new Factory)->withServiceAccount('/path/to/serviceAccount.json');
    $auth = $firebase->createAuth();
    $decoded = $auth->verifyIdToken($idToken);
    if ($decoded->claims()->get('sub') !== $uid) {
        http_response_code(401);
        echo json_encode(['error' => 'UID mismatch']);
        exit;
    }
}

$stmt = $pdo->prepare('SELECT * FROM users WHERE social_provider = ? AND social_id = ?');
$stmt->execute([$provider, $uid]);
$user = $stmt->fetch();

if (!$user) {
    $pdo->prepare('INSERT INTO users (social_provider, social_id, email, name) VALUES (?, ?, ?, ?)')
        ->execute([$provider, $uid, $email, $displayName]);
    $userId = $pdo->lastInsertId();
} else {
    $userId = $user['id'];
}

$_SESSION['user_id'] = $userId;
echo json_encode(['ok' => true, 'userId' => $userId]);

On this page