What you will learn
This lab teaches you to observe a sign-in session without exposing its credential. You will connect explicit login, session-check and logout buttons to documented Gammal Tech methods, then record what the interface does. The page reports session-related state only; it does not establish application permissions or prove that a customer has paid.
Start with a ready, authorized practice project
Complete the first-project exercise before this lab: use your verified individual account, an authorized registered HTTPS domain and the official SDK loaded once before your application script. The examples below belong inside that practice page. They depend on the documented GammalTech global being available.
Use no customer records, payment flow or paid entitlement in this exercise. If another learner participates, each person uses their own account without sharing credentials. Your deliverable is a session behavior record, the page source and safe screenshots showing status messages. None should contain a session token.
Read the official SDK method descriptions before running the exercise. Keep the implementation small enough that you can explain every event handler.
Distinguish three different observations
SDK readiness means a library and its methods loaded. Sign-in state is the state the SDK reports for the current browser tab. Authorization is the decision that a particular action is allowed. These observations are related, but none should silently stand in for another.
The documented helpers include isLoggedIn(), onAuth(onIn, onOut) and verify(). The published SDK guide does not define a resolved payload schema for verify(), so this exercise does not read invented fields such as result.valid. After an action, it refreshes the displayed SDK state. It never treats promise resolution alone as permission to access a record or release a purchase.
OWASP's session guidance explains the sensitivity of a session credential. You can learn the flow without printing that credential or adding it to a URL.
Add three explicit controls
Add this markup in the page body before your application script. The buttons have visible names, and status text can be announced by assistive technology. There is no automatic login on page load.
<p id="auth-state" role="status" aria-live="polite">
Checking sign-in state…
</p>
<p id="action-message" role="status" aria-live="polite"></p>
<button id="sign-in" type="button">Sign in</button>
<button id="check-session" type="button">Check session</button>
<button id="sign-out" type="button">Sign out</button>A single clear interface makes the exercise observable. The sign-in button starts the login process after a deliberate user click. The session-check button is a separate action, so you can distinguish it from opening the page. The sign-out button gives you a repeatable way to observe a change in the current session.
Keep credentials out of the interface
Place the next block in your application script after the markup and SDK load. It prevents overlapping button actions during this small exercise, renders text safely and uses a fixed message if an operation fails.
const state = document.getElementById("auth-state");
const message = document.getElementById("action-message");
const buttons = ["sign-in", "check-session", "sign-out"]
.map(id => document.getElementById(id));
let busy = false;
function render() {
state.textContent = GammalTech.isLoggedIn()
? "SDK reports signed in for this tab."
: "SDK reports signed out for this tab.";
}
async function perform(task) {
if (busy) return;
busy = true;
buttons.forEach(button => { button.disabled = true; });
message.textContent = "Working…";
try {
await task();
render();
message.textContent = "Action completed. Read the tab state.";
} catch {
message.textContent = "Unable to finish. Please try again later.";
} finally {
busy = false;
buttons.forEach(button => { button.disabled = false; });
}
}
render();Now add the event wiring immediately below that block:
buttons[0].addEventListener("click", () =>
perform(() => GammalTech.login()));
buttons[1].addEventListener("click", () =>
perform(() => GammalTech.verify()));
buttons[2].addEventListener("click", () =>
perform(() => GammalTech.logout()));
GammalTech.onAuth(render, render).catch(() => {
message.textContent = "Sign-in state is unavailable. Try again later.";
});The call to login() occurs directly from the click handler through perform. Its returned token is deliberately unused. No exception detail is printed. The buttons becoming disabled is a user-interface convenience, not an authorization control. The SDK has its own network retry behavior; do not add a loop that repeatedly invokes login or other actions.
Run the acceptance cases and record actual behavior
| Case | Expected observation | Evidence to keep |
|---|---|---|
| Open the page | Status appears without a forced login popup | Safe initial screenshot |
| Click Sign in and complete the flow | The interface refreshes the reported tab state | State text, without credentials |
| Click Check session | The documented method runs; the UI does not invent a verification payload | Observed action and state |
| Click Sign out | The UI reflects the resulting signed-out state | State text after completion |
| Cancel login or encounter a failure | No exception or token is exposed; controls remain usable | Observed behavior and a note |
Record what happened, including whether cancellation rejects or leaves the state unchanged. The guide does not specify every cancellation representation, so do not write an expected error string that the SDK never promised. For a check you did not run, write “not tested.”
Investigate one common misunderstanding
The documentation describes a tab-based session and a new login for a fresh or reopened tab. Try that behavior in your authorized environment and record each tab separately. Do not infer that closing a tab revokes every session, erases every browser trace or signs the person out on every device.
A common mistake is adding getToken() output to a debug label because the login state seems unclear. Avoid that shortcut. The exercise needs a state description, not the credential carrying the session. Screenshots and copied network records can travel far beyond the original learning environment.
If the displayed state appears stale after a failure, describe that limitation in the test record and rerun a documented state check. A status label is an observation, not independent proof that a remote session is valid. Do not reuse this demo label as a production access gate.
Finish with a boundary statement and your next test
Write a short boundary statement: “This page demonstrates documented session methods and status handling. It does not decide who may administer the application, change a price or receive a paid product.” Add a sentence explaining why a hidden button or editable preference cannot make those decisions trustworthy.
OWASP's authorization guidance treats permission checks as a separate responsibility. In the next data exercise, use an ordinary preference that the learner is allowed to change. Keep authoritative roles, payment status and fulfillment decisions out of that record.
Your completed record should identify the domain, exercise version, cases run, outcomes and unresolved questions. This gives another person enough information to review your learning without seeing any private account material.
Common questions
Why not display the token to prove login worked?
A token is sensitive session material, not a demonstration badge. Use the documented state helpers and record visible behavior without exposing the credential.
Does verify() let the frontend authorize a paid feature?
A session check and a paid entitlement answer different questions. This lab does not interpret an undocumented verify payload or use browser state as trusted payment or authorization evidence.
Lesson references
Documentation checked on 12 October 2026. Recheck current documentation before implementing or quoting a client project.