This page is strictly for learning purposes and all the data is dummy

Programmers Picnic 0 to Infinity Lesson

Google Identity Services

Learn how to add Sign in with Google to GitHub Pages, static websites, learning portals, student dashboards, and serious applications.

1. What Is Google Identity Services?

Google Identity Services, often shortened to GIS, is Google’s modern browser library for adding Google sign-in to websites and web applications.

It allows a user to click a familiar Sign in with Google button. Google then authenticates the user and sends your web page a credential response. That response contains an ID token, which is a signed token containing identity information such as the user’s name, email, profile picture, and Google account ID.

Full form: GIS means Google Identity Services. JWT means JSON Web Token. OAuth means Open Authorization.

The simplest flow

User opens your page
        ↓
User clicks Sign in with Google
        ↓
Google verifies the user
        ↓
Your page receives an ID token
        ↓
Your page reads user name and email
        ↓
Your page shows protected content
Advertisement space. Google AdSense can display an ad here after you add an ad unit.

2. Why Use Google Login?

For a learning website, Google login is useful because many students already have Gmail accounts. You do not need to build a password system at the beginning.

Good for Student identity, personalized welcome, simple gated pages, attendance, lesson progress, and dashboard prototypes.
Not enough for Strong paid course protection, private marks, certificates, financial records, and admin-only databases without a backend.

Static website reality

GitHub Pages can host HTML, CSS, and JavaScript. It cannot secretly verify a token on the server because there is no server code running on GitHub Pages. So GitHub Pages login is useful for a front-end gate, but not for strong security.

3. Create the Google OAuth Client ID

Before your page can use Google Identity Services, you need a web application client ID from Google Cloud. Google’s setup guide says a Google API client ID is required before enabling Google Identity Services on a website.

Steps

  1. Open Google Cloud Console.
  2. Open Google Auth Platform.
  3. Create or select a project.
  4. Configure the consent screen.
  5. Create an OAuth client.
  6. Choose Web application.
  7. Add authorized JavaScript origins.
  8. Copy the client ID.

For GitHub Pages

Authorized JavaScript origin:
https://programmer-s-picnic.github.io

For your own domains

Authorized JavaScript origins:
https://www.learnwithchampak.live
https://learnwithchampak.live
https://editor.learnwithchampak.live
https://aiml.learnwithchampak.live
Do not add the full page path as an origin. Add only the scheme and domain, for example https://programmer-s-picnic.github.io, not https://programmer-s-picnic.github.io/json-images/links/index.html.

4. The Minimal Google Login Page

A minimal GIS page needs three things:

  1. The GIS script
  2. Your Google OAuth client ID
  3. A callback function to receive the credential
<script src="https://accounts.google.com/gsi/client" async defer></script>

<div
  id="g_id_onload"
  data-client_id="YOUR_CLIENT_ID"
  data-callback="handleCredentialResponse">
</div>

<div class="g_id_signin"></div>

<script>
  function handleCredentialResponse(response) {
    console.log(response.credential);
  }
</script>
Checkpoint: After opening the page in a browser, you should see a Google sign-in button.

5. What Is the ID Token?

After successful sign-in, Google gives your JavaScript callback a credential. This credential is an ID token. It is usually a JWT, which has three parts:

header.payload.signature
Part Meaning
Header Metadata about the token and signing algorithm.
Payload User identity information and token claims.
Signature Cryptographic proof that the token was signed by Google.
In browser-only demos, we may decode the token to read the name and email. But for real security, a backend must verify the token signature and claims.

6. Decode the User Data in the Browser

For a static demo, you can decode the token payload in JavaScript.

function parseJwt(token) {
  const base64Url = token.split(".")[1];
  const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");

  const jsonPayload = decodeURIComponent(
    atob(base64)
      .split("")
      .map(function(c) {
        return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
      })
      .join("")
  );

  return JSON.parse(jsonPayload);
}

function handleCredentialResponse(response) {
  const user = parseJwt(response.credential);

  console.log(user.name);
  console.log(user.email);
  console.log(user.picture);
}

Common useful fields

Field Meaning
name User’s display name.
email User’s email address.
picture User’s profile image.
sub Stable Google account identifier. This is better than email for long-term identity.
aud Audience. It should match your client ID in real verification.
iss Issuer. It should be Google.
exp Expiry time.

7. Allow Only Selected Users

For a simple GitHub Pages gate, you can allow only selected email addresses.

const allowedEmails = [
  "champaksworld@gmail.com",
  "student1@gmail.com",
  "student2@gmail.com"
];

if (!allowedEmails.includes(user.email)) {
  alert("Sorry, this email is not allowed.");
  return;
}
This is not strong security. Anyone who can edit JavaScript in the browser can bypass a front-end check. Use it for basic access control, not for private records or paid content.

8. Use a Separate users.json File

Instead of editing your HTML every time you add a student, keep allowed users in a JSON file.

users.json

[
  "champaksworld@gmail.com",
  "student1@gmail.com",
  "student2@gmail.com"
]

Load it from GitHub Pages

async function getAllowedEmails() {
  const response = await fetch(
    "https://programmer-s-picnic.github.io/json-images/links/users.json",
    { cache: "no-store" }
  );

  if (!response.ok) {
    throw new Error("Could not load users.json");
  }

  return await response.json();
}

Use it during login

async function handleCredentialResponse(response) {
  const user = parseJwt(response.credential);
  const allowedEmails = await getAllowedEmails();

  const normalizedEmail = String(user.email || "").toLowerCase().trim();

  if (!allowedEmails.map(e => e.toLowerCase().trim()).includes(normalizedEmail)) {
    alert("Sorry, this email is not allowed.");
    return;
  }

  localStorage.setItem("google_user", JSON.stringify(user));
  showUser(user);
}
Checkpoint: After adding a new Gmail address to users.json, that user should be able to log in without changing the HTML page.

9. Logout Correctly

Your page may store the user in localStorage so the welcome message remains after refresh. On logout, remove that local data.

function logout() {
  localStorage.removeItem("google_user");

  if (window.google && google.accounts && google.accounts.id) {
    google.accounts.id.disableAutoSelect();
  }

  location.reload();
}

Google’s JavaScript reference includes google.accounts.id.disableAutoSelect() for sign-out behavior so the sign-in flow does not immediately auto-select the same user again.

10. Deploy on GitHub Pages

Recommended files

json-images/
  links/
    index.html
    users.json
    privacy-policy.html
    terms.html

Published URLs

Login page:
https://programmer-s-picnic.github.io/json-images/links/index.html

Allowed users file:
https://programmer-s-picnic.github.io/json-images/links/users.json

Google Cloud origin

https://programmer-s-picnic.github.io
Checkpoint: Open your GitHub Pages login page. If the OAuth origin is correct, the Google button should appear and login should not show an origin mismatch error.

11. The Security Truth

This is the most important chapter.

Method Security Level Use Case
HTML + JavaScript only Basic Personalization, simple demos, non-sensitive lesson gates.
HTML + users.json Basic Easy student list management, still visible publicly.
Firebase Authentication Good Real user login, Firestore rules, student progress.
Backend token verification Strong Paid courses, certificates, admin panels, private data.
A static page can hide content visually, but it cannot truly protect secret data. Anything shipped to the browser should be considered visible to a determined user.

12. Backend Verification: The Professional Way

In a production application, the browser should send the ID token to your backend. The backend should verify it using Google’s official libraries.

Google’s backend authentication guidance says the backend should verify that the ID token is properly signed, that the aud claim matches one of your client IDs, that the issuer is Google, and that the token has not expired.

Backend flow

Browser receives ID token
        ↓
Browser sends token to backend
        ↓
Backend verifies token signature
        ↓
Backend checks aud, iss, exp
        ↓
Backend creates its own session
        ↓
Backend serves protected data

Node.js style example

// Conceptual backend example.
// This code belongs on a server, not GitHub Pages.

import { OAuth2Client } from "google-auth-library";

const client = new OAuth2Client("YOUR_CLIENT_ID");

async function verifyGoogleToken(idToken) {
  const ticket = await client.verifyIdToken({
    idToken: idToken,
    audience: "YOUR_CLIENT_ID"
  });

  const payload = ticket.getPayload();

  return {
    googleId: payload.sub,
    email: payload.email,
    name: payload.name,
    picture: payload.picture
  };
}
This is the correct path when your app handles private data, payments, certificates, student records, dashboards, or admin actions.

13. Firebase Authentication Path

For your learning system, Firebase Authentication is often easier than writing your own backend. You can host the front end on GitHub Pages and use Firebase for real authentication and database rules.

Recommended architecture

GitHub Pages
  └── HTML, CSS, JavaScript

Firebase Authentication
  └── Google login

Firestore Database
  └── users
  └── courses
  └── progress
  └── roles
  └── query limits

Use Firebase when you need

  • Student progress
  • Role-based access
  • Admin users
  • Paid student lists
  • Query limits such as 10 support queries per week
  • Safer course dashboards

14. Complete GitHub Pages Login Code

Replace the client ID only if needed. This example loads allowed users from:

https://programmer-s-picnic.github.io/json-images/links/users.json
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <title>Google Login on GitHub Pages</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />

  <script src="https://accounts.google.com/gsi/client" async defer></script>

  <style>
    body {
      font-family: Arial, sans-serif;
      background: #fff7ed;
      color: #1f2937;
      padding: 40px;
      text-align: center;
    }

    .card {
      max-width: 560px;
      margin: auto;
      background: white;
      padding: 30px;
      border-radius: 18px;
      box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08);
      border-top: 6px solid #f97316;
    }

    #protectedContent {
      display: none;
      margin-top: 25px;
      padding: 20px;
      background: #fffbeb;
      border-radius: 14px;
      border: 1px solid #fed7aa;
      text-align: left;
    }

    #loginError {
      display: none;
      margin-top: 18px;
      padding: 14px;
      background: #fef2f2;
      color: #7f1d1d;
      border: 1px solid #fecaca;
      border-radius: 12px;
    }

    .profile-row {
      display: flex;
      gap: 14px;
      align-items: center;
    }

    .profile-row img {
      width: 60px;
      height: 60px;
      border-radius: 50%;
      border: 3px solid #fed7aa;
    }

    button {
      margin-top: 20px;
      padding: 10px 18px;
      border: none;
      border-radius: 10px;
      background: #ea580c;
      color: white;
      cursor: pointer;
      font-weight: bold;
    }
  </style>
</head>

<body>

  <div class="card">
    <h1>Programmers Picnic Login</h1>
    <p>Sign in with Google to continue.</p>

    <div
      id="g_id_onload"
      data-client_id="704346946203-m69uok3l8htbtgdsee0vtoul5b8v7clv.apps.googleusercontent.com"
      data-callback="handleCredentialResponse">
    </div>

    <div
      class="g_id_signin"
      data-type="standard"
      data-size="large"
      data-theme="outline"
      data-text="signin_with"
      data-shape="pill"
      data-logo_alignment="left">
    </div>

    <div id="loginError"></div>

    <div id="protectedContent">
      <div class="profile-row">
        <img id="userPicture" src="" alt="User profile picture" />
        <div>
          <h2 id="welcomeText"></h2>
          <p id="userEmail"></p>
        </div>
      </div>

      <p>You are now logged in.</p>
      <p>This content is visible only after Google login.</p>

      <button onclick="logout()">Logout</button>
    </div>
  </div>

  <script>
    const USERS_JSON_URL =
      "https://programmer-s-picnic.github.io/json-images/links/users.json";

    function showError(message) {
      const box = document.getElementById("loginError");
      box.style.display = "block";
      box.textContent = message;
    }

    function clearError() {
      const box = document.getElementById("loginError");
      box.style.display = "none";
      box.textContent = "";
    }

    function parseJwt(token) {
      const base64Url = token.split(".")[1];
      const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");

      const jsonPayload = decodeURIComponent(
        atob(base64)
          .split("")
          .map(function(c) {
            return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
          })
          .join("")
      );

      return JSON.parse(jsonPayload);
    }

    async function getAllowedEmails() {
      const response = await fetch(USERS_JSON_URL, { cache: "no-store" });

      if (!response.ok) {
        throw new Error("Could not load users.json");
      }

      const emails = await response.json();

      if (!Array.isArray(emails)) {
        throw new Error("users.json must be an array of email addresses");
      }

      return emails.map(function(email) {
        return String(email).toLowerCase().trim();
      });
    }

    async function handleCredentialResponse(response) {
      try {
        clearError();

        const user = parseJwt(response.credential);
        const allowedEmails = await getAllowedEmails();

        const userEmail = String(user.email || "").toLowerCase().trim();

        if (!allowedEmails.includes(userEmail)) {
          showError("Sorry, this email is not allowed: " + user.email);
          return;
        }

        localStorage.setItem("google_user", JSON.stringify(user));
        showUser(user);

      } catch (error) {
        console.error(error);
        showError("Login failed. " + error.message);
      }
    }

    function showUser(user) {
      document.getElementById("protectedContent").style.display = "block";

      document.getElementById("welcomeText").innerText =
        "Welcome, " + (user.name || user.email);

      document.getElementById("userEmail").innerText =
        user.email || "";

      if (user.picture) {
        document.getElementById("userPicture").src = user.picture;
      }
    }

    function logout() {
      localStorage.removeItem("google_user");

      if (window.google && google.accounts && google.accounts.id) {
        google.accounts.id.disableAutoSelect();
      }

      location.reload();
    }

    window.onload = function() {
      const savedUser = localStorage.getItem("google_user");

      if (savedUser) {
        showUser(JSON.parse(savedUser));
      }
    };
  </script>

</body>
</html>

15. Final Checkpoints

Checkpoint 1: Files created

These files should exist:

index.html
users.json
privacy-policy.html
terms.html

Checkpoint 2: users.json works

Open this in the browser:

https://programmer-s-picnic.github.io/json-images/links/users.json

You should see something like:

[
  "champaksworld@gmail.com"
]

Checkpoint 3: Login page opens

Open your login page:

https://programmer-s-picnic.github.io/json-images/links/index.html

You should see:

Programmers Picnic Login
Sign in with Google to continue.
[Sign in with Google button]

Checkpoint 4: Allowed user can enter

Sign in with an email listed in users.json. You should see:

Welcome, Your Name
You are now logged in.
This content is visible only after Google login.

Checkpoint 5: Unlisted user is blocked

Sign in with an email not listed in users.json. You should see:

Sorry, this email is not allowed.
You now understand Google Identity Services from the beginner level to the professional architecture level: simple button, ID token, user decoding, allowed users, GitHub Pages deployment, security limits, backend verification, and Firebase upgrade path.