Skip to main content

Module login

Module login 

Source
Expand description

grab auth login: a real phone login on weblogin.grab.com, driven over CDP inside an isolated browser context.

grabcli does not replay or forge the login page’s anti-bot tokens (reCAPTCHA Enterprise, the x-hydraweb-jwt fingerprint). Instead it opens food.grab.com/auth/login in a fresh Target.createBrowserContext context (own cookie jar, shared with no other tab, so nothing else in the browser can log it out) and lets the real page do its own checks, the way a person would. grabcli only:

  1. types the phone number and keeps “Remember me … 60 days” ticked;
  2. clicks Continue and, if Grab offers a choice, picks ONE challenge (in-app approval or OTP) — this is the only step that sends anything;
  3. later (same or another process) types the OTP, or waits for the in-app approval;
  4. lets the page redirect through food.grab.com/auth/callback inside the context, reads the context’s cookies with Storage.getCookies, saves them as the session and disposes the context.

The context outlives the process (disposeOnDetach: false); what’s needed to resume (context/tab ids, expiry, the masked phone) is the PendingLogin value, which the caller keeps (the CLI in a 0600 file, a daemon in memory). The step functions take it as &mut Option<_> and set it to None once the login is over (logged in, or ended for good). Sends are rate-limited by an injectable SendBudget and never retried.

This module writes no files and logs nothing: it never prints cookie values, tokens, OTPs or the full phone number. LoginDriver wraps the steps as a small state machine for daemons (one driver per login, driven from a thread via block_on or from a task).

Structs§

LoginDriver
A phone login as a state machine, for a daemon: start sends ONE challenge (after the injected SendBudget allows it), then submit_code or poll until the state is terminal, or cancel. Writes no files and logs nothing. The isolated browser context is disposed when the login ends; call cancel when abandoning a driver so it is disposed promptly (an abandoned one is otherwise only cleaned up by the browser).
LoginRequest
What to start a LoginDriver with.
MemorySendBudget
A SendLog held in memory.
PendingLogin
State kept between --phone … and --otp / --poll. No secrets: ids of the isolated context/tab in the browser and a masked phone.
SendLog
Timestamps of challenge sends, kept separately from the pending login so cancelling a login never resets the limits. A plain value: persisting it is up to the SendBudget that holds it.
StartOpts
Options for start.

Enums§

Channel
Which challenge to ask Grab for.
LoginState
What a LoginDriver is waiting for, or how it ended. Carries no phone number or code (only the masked phone) and redacts the session in Debug.
PendingKind
What the send produced.
Screen
Where the weblogin page is, from PROBE_JS.
WaitOutcome
Outcome of wait_for_approval.

Constants§

LOGIN_START_URL
Where the browser login starts (redirects to weblogin.grab.com).
MAX_SENDS_PER_HOUR
Maximum challenge sends in any rolling hour.
PENDING_TTL_SECS
How long a started login stays resumable. Grab’s codes live ~5 min.
PROBE_JS
Read-only probe of the login tab. Returns structure and fixed UI strings only; the CLI never prints text.
SEND_COOLDOWN_SECS
Minimum gap between two challenge sends.

Traits§

SendBudget
The challenge-send budget (SEND_COOLDOWN_SECS, MAX_SENDS_PER_HOUR). Injectable so the caller decides its scope and storage: the CLI keeps one per user in a file; a daemon keeps one per org.

Functions§

cancel
grab auth login --cancel: dispose the isolated context, forget the pending login (clearing slot). Send limits are kept. Returns whether there was one.
check_no_pending
Before start: refuse while an unexpired login is pending; dispose an expired one (and clear slot).
classify_screen
dry_run_plan
What --phone … would do, without doing it (--dry-run).
finish_with_otp
grab auth login --otp <code>: type the code into the waiting page. prev is the session to build on (its preference cookies are kept); pass &Session::default() for none. On success (and on a terminal failure) slot is cleared; a rejected code leaves it for another try.
mask_phone
+63••••••••12: the country code and the last two digits only.
order_tracking_tabs
food.grab.com tabs in the shared browser that poll order tracking. When the browser’s food session lapses, such a tab gets 401s from /track and the page then calls GrabID oauth2/logout + food /auth/logout (every ~16 s), which logs the browser out again right after any login there. The isolated login context is immune, but these tabs still break grab auth import and normal browsing. grabcli never closes them.
pending_json
stdout document after --phone (or a --poll that is still waiting).
pick_option
Pick the challenge option to click for channel, if Grab offers one.
shared_browser_tabs
Order-tracking tabs in the shared browser (best-effort; empty if the browser is unreachable). /json can still list a tab for a moment after it was closed, so a non-empty answer is re-checked once after a short delay and only tabs seen both times are reported.
split_phone
Split +<cc><national> into (cc, national digits). Spaces, dashes, dots and parentheses are ignored; a trunk 0 is dropped.
start
Start a login and send exactly ONE challenge. The caller has already decided a send is wanted, that silent refresh failed, and that no other login is pending (see check_no_pending). Returns the pending login to keep for finish_with_otp / wait_for_approval.
still_open
Tabs present in both listings.
tracking_tab_warning
wait_for_approval
grab auth login --poll: wait up to timeout for the in-app approval. Same slot / prev rules as finish_with_otp.