WebアプリとGoogleログイン機能

①まずは下記のURLにログインした状態で「APIとサービス」に移動※プロジェクトを作成する
https://console.cloud.google.com/
![手順1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957418/79487b7f-3fed-9911-2911-c9bc2344d833.png)

②「認証情報」をクリック
![手順2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957418/69b733d8-60cf-30a5-9958-3222aada0c70.png)

③「認証情報を作成」の「OAuthクライアントID」を選択
![手順3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957418/a6cd5b9e-7664-88ad-118d-dacc7c560faf.png)

④「承認済みの JavaScript 生成元」（使用するURLのドメイン）を設定

⑤「承認済みのリダイレクト URIを設定」（ログイン認証するURL）

Googleログインを実装するページ[index.php]
Googleにトークンを送信する処理[session_handler.php]
Googleの認証OKの場合に移動するページ[dashboard.php]

![Googleログインの流れ図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957418/ec411352-a918-c965-986f-ae5045d68660.png)


index.php
```
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Googleログイン</title>
    <!-- Google Identity Servicesライブラリ -->
    <script src="https://accounts.google.com/gsi/client" async defer></script>
    <script src="https://cdn.jsdelivr.net/npm/jwt-decode/build/jwt-decode.min.js"></script>
</head>
<body>
    <!-- Googleログインボタン -->
    <div id="g_id_onload"
         data-client_id="GoogleのAPIとサービスで取得したID"
         data-callback="handleCredentialResponse"
         data-auto_prompt="false">
    </div>
    <div class="g_id_signin" data-type="standard"></div>

    <h1>ユーザー情報</h1>
    <div id="user-info"></div>

<script>
async function handleCredentialResponse(response) {
    try {
        // セッション保存用のエンドポイントにPOSTリクエストを送信
        const serverResponse = await fetch('./session_handler.php', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({ credential: response.credential })
        });

        if (!serverResponse.ok) {
            throw new Error(`HTTP error! status: ${serverResponse.status}`);
        }

        const responseData = await serverResponse.json();
        if (responseData.status === 'success') {
            alert('Authentication successful! Redirecting to dashboard...');
            window.location.href = './dashboard.php';
        } else {
            throw new Error(responseData.message || 'Unknown error occurred');
        }
    } catch (error) {
        console.error('Unexpected error in handleCredentialResponse:', error);
        alert('An unexpected error occurred. Please try again later.');
    }
}

</script>
</body>
</html>
```


session_handler.php
```
<?php
session_start();

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $data = json_decode(file_get_contents('php://input'), true);

    if (isset($data['credential'])) {
        $credential = $data['credential'];

        // Googleトークンを検証してユーザー情報を取得（GoogleのAPIを利用する例）
        $userInfo = verifyGoogleToken($credential);

        if ($userInfo) {
            // セッションに保存
            $_SESSION['user'] = $userInfo;

            // 成功レスポンスを返す
            echo json_encode(['status' => 'success']);
        } else {
            http_response_code(400);
            echo json_encode(['status' => 'error', 'message' => 'Invalid Google credential']);
        }
    } else {
        http_response_code(400);
        echo json_encode(['status' => 'error', 'message' => 'Credential not provided']);
    }
}

function verifyGoogleToken($credential) {
    // トークンをデコードして検証する（GoogleのAPIを使う方法の一例）
    $url = 'https://oauth2.googleapis.com/tokeninfo?id_token=' . $credential;

    $response = file_get_contents($url);
    $userInfo = json_decode($response, true);

    if (isset($userInfo['sub'])) {
        return [
            'id' => $userInfo['sub'],
            'name' => $userInfo['name'],
            'email' => $userInfo['email'],
            'picture' => $userInfo['picture']
        ];
    }

    return null;
}
?>
```

dashboard.php
```
<?php
session_start();

if (!isset($_SESSION['user'])) {
    // 未ログインの場合はログインページにリダイレクト
    header('Location: index.php');
    exit;
}

$user = $_SESSION['user'];

?>

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Dashboard</title>
<style>
* {
  margin: 0;
  padding: 0;
}

.app {
  width: 100vw;
  height: 100vh;
  display: flex;
  flex-direction: column;
}

.header {
  height: auto;
  background-color: lightcyan;
  box-sizing: border-box;
  border: 8px solid blue;
}

.main {
  display: flex;
  flex-direction: row;
  flex-grow: 1;
}

.sideBar {
  width: auto;
  background-color: moccasin;
  box-sizing: border-box;
  border: 8px solid chocolate;
}

.content {
  display: flex;
  flex-direction: column;
  flex-grow: 1;
}

.flex-content {
  flex-grow: 1;
  background-color: palegoldenrod;
  box-sizing: border-box;
  display: flex;
  flex-direction: row;
  border: 8px solid green;
}

.fixed-content {
  background-color: thistle;
  box-sizing: border-box;
  border: 8px solid darkmagenta;
}

.Edit_Area textarea,
.Edit_Area a {
    width: 50%;
    box-sizing: border-box; /* パディングやボーダーを含めた幅計算 */
}
.Edit_Area a img {
    width: 100%; /* 子要素の幅を50%に設定 */
    box-sizing: border-box; /* パディングやボーダーを含めた幅計算 */
}
</style>
</head>
<body class="app">

<div class="header">
            <h1>Welcome, <?php echo htmlspecialchars($user['name']); ?>!</h1>
            <p>Email: <?php echo htmlspecialchars($user['email']); ?></p>
            <img src="<?php echo htmlspecialchars($user['picture']); ?>" alt="Profile Picture">
</div>

<script>
</script>
</body>
</html>
```