はじめに
Microsoft EntraIDのExternal IDを使ってGoogleログインを実装する方法を紹介します。
GCPではFirebase AuthやGoogle Identity Platformを使ってGoogleログインを実装することが出来ますが、AzureでもMicrosoft EntraIDのExternal IDを使ってGoogleログインを実装することが可能だったりします。
ユーザー名とパスワードでログインももちろん良いですが、Googleログインもあった方がユーザー体験が向上するので、今回はMicrosoft EntraIDのExternal IDを使ってGoogleログインを実装してみたいと思います。
ユーザー名 + passwordでログインするハンズオンはこちらです。
今回のハンズオンのサンプルコードを以下に配置していますのでご参照ください。
https://github.com/SatakeYusuke19920527/azure-externalid-google-federation
それではハンズオン開始🖐️
環境構築
次にローカルへcloneです。
以下のコマンドでNext.jsプロジェクトを作成します。
create-next-app . --ts
npm run dev で動作確認し、Next.jsのtemplateが表示されればOKです。
Microsoft Entra 外部 IDで Google フェデレーションを構成する
EntraIDの管理画面にアクセスします。
External Identities > すべての ID プロバイダーからIDプロバイダーにGoogleを追加しにいきます。

クライアントIDとクライアントシークレットを記載と書かれているので、今からこれらを入手しにGoogle Developer Consoleへアクセスします。

まずは、Google Developer Consoleへアクセスします。
https://console.cloud.google.com/apis
projectが作成出来ると、ダッシュボードはこんな感じになります

OAuth同意画面でUser Typeを外部に設定し作成します。

[OAuth 同意画面] の [アプリ情報] で、アプリケーションの [名前] を入力します。
[ユーザー サポートのメール] のアドレスを選択します。
[認可済みドメイン] セクションで、[ドメインの追加] を選択し、ciamlogin.com と microsoftonline.com を追加します。

追加するURLは以下です。
- https://login.microsoftonline.com
- https://login.microsoftonline.com/te//oauth2/authresp
- https://login.microsoftonline.com/te/.onmicrosoft.com/oauth2/authresp
- https://.ciamlogin.com//federation/oidc/accounts.google.com
- https://.ciamlogin.com/.onmicrosoft.com/federation/oidc/accounts.google.com
- https://.ciamlogin.com//federation/oauth2
- https://.ciamlogin.com/.onmicrosoft.com/federation/oauth2
tenantIDとtenant-subdomainはEntraIDの管理画面にアクセスして確認してください。
これでようやくクライアントIDとクライアントシークレット取得することが出来ました。

EntraIDのポータルに戻り、クライアントIDとクライアントシークレットを入力します。

IDプロバイダーより、Googleが構成済みになればOKです。

Microsoft Entra ID でユーザーフローにGoogleIDプロバイダーを追加する
Entra管理センターから、Googleログインする為の新しいユーザーフローを作成します。

ユーザーフロー追加してください。
IDプロバイダーはGoogleを選択です。

そして、先ほど作成したユーザーフローにアプリケーションを紐付けます。

これで準備完了です、次は実装に移ります。
Next.jsの実装
VSCodeより、Next.jsのプロジェクトを開きます。
msal-reactをインストールします。
npm install @azure/msal-react
それぞれ実装していきます。
import { Providers } from '@/components/Providers';
import { Inter } from 'next/font/google';
import './globals.css';
const inter = Inter({ subsets: ['latin'] });
export const metadata = {
  title: 'External ID',
  description: 'Generated by create next app',
};
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="ja">
      <body className={inter.className}>
        <Providers>{children}</Providers>
      </body>
    </html>
  );
}
'use client';
import useCurrentUser from '@/hooks/useCurrentUser';
import { loginRequest } from '@/lib/msalConfig';
import { useMsal } from '@azure/msal-react';
import { useEffect } from 'react';
export default function Home() {
  const { instance, accounts } = useMsal();
  const user = useCurrentUser();
  useEffect(() => {
    console.log('🚀 ~ SideMenu ~ user:', user);
    console.log('🚀 ~ SideMenu ~ accounts:', accounts);
  }, [accounts]);
  return (
    <main>
      <h1
        onClick={() =>
          user === null
            ? instance.loginRedirect(loginRequest)
            : instance.logout()
        }
        className="flex justify-center px-4 text-2xl font-bold cursor-pointer"
      >
        {user === null ? 'login' : 'logout'}
      </h1>
      <h1>
        {user === null
          ? 'Please login to see your profile'
          : `Welcome ${user?.user_name}! 🚀 Warm Welcome 🚀 Your email: ${user?.email} && ${user?.sub}`}
      </h1>
    </main>
  );
}
import { AccountInfo } from '@azure/msal-browser';
import { useMsal } from '@azure/msal-react';
interface Account extends AccountInfo {
  idTokenClaims: {
    aud: string;
    iss: string;
    iat: number;
    nbf: number;
    exp: number;
    idp: string;
    name: string;
    nonce: string;
    oid: string;
    preferred_username: string;
    rh: string;
    sub: string;
    tid: string;
    uti: string;
    ver: string;
  };
}
export interface User {
  sub: string;
  user_name: string;
  email: string;
}
const useCurrentUser = (): User | null | undefined => {
  const { accounts } = useMsal();
  console.log("🚀 ~ useCurrentUser ~ accounts:", accounts)
  if (accounts.length > 0) {
    const account = accounts[0] as Account;
    const user: User = {
      sub: account.idTokenClaims?.aud,
      user_name: account.idTokenClaims?.name,
      email: account.idTokenClaims?.preferred_username,
    };
    return user;
  }
  return null;
};
export default useCurrentUser;
'use client';
import { msalConfig } from '@/lib/msalConfig';
import { PublicClientApplication } from '@azure/msal-browser';
import { MsalProvider } from '@azure/msal-react';
import React from 'react';
const msalInstance = new PublicClientApplication(msalConfig);
export function Providers({ children }: { children: React.ReactNode }) {
  return <MsalProvider instance={msalInstance}>{children}</MsalProvider>;
}
export const msalConfig = {
  auth: {
    clientId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx', // Azure ポータルで取得したクライアントID
    authority:
      'https://login.microsoftonline.com/xxxx-xxxx-xxxxx-xxxx-xxxxxxxx', // テナントID
    redirectUri: 'http://localhost:3000', // リダイレクトURI
  },
  cache: {
    cacheLocation: 'sessionStorage', // キャッシュの場所
    storeAuthStateInCookie: false, // IE11やEdgeをサポートする場合はtrueに設定
  },
};
export const loginRequest = {
  scopes: ['User.Read'],
};
これにて実装は完了です。
動作確認
では実行してみましょう。
npm run dev
Loginというボタンをクリックしてみてください。
これでMicrosoft EntraIDでGoogleログインが実装されました。
お疲れ様でした👋
参考文献















