Haeminway haeminway
한국어
Back to Tech Notes
1 min read

One Deploy Setting Decides Your Security Model: Execute as / Access

The 'execute as' × 'who can access' combination sets data permissions and whether your code is exposed. Public apps need their own app-level auth.

A web app’s two deploy choices: “whose permissions it runs as” and “who can access it”: set the security model. Decide before coding and write it down, or you get a permissions accident later.

Execute asMeaningWatch out
Me (deployer)Always runs with deployer’s permissionsWrong for apps needing per-user separation
User accessingRuns with the visitor’s permissionsNeeds user OAuth consent + missing-scope handling

Why it matters

Deploy as “Me” to “Anyone” and anyone who visits can touch sheets and mail with the deployer’s permissions. Without separate input validation and auth, a public endpoint is wide open. The cost is a data leak or abuse.

Honest pitfall: source exposure

Deploying to “Anyone with a Google account” requires project sharing, so the customer can read your source. If closed source is a contract term, go with “Me + Anyone” plus your own app-level auth (email code + CacheService expiry, etc.).

Guard a public doPost with tiers

function doPost(e) {
  try {
    const body = JSON.parse(e.postData.contents || "{}");
    if (!ALLOWED.has(body.action)) throw new Error("unknown action");
    // never dispatch a function name straight from the payload (allowlist only)
    return json({ ok: true, result: handle(body) });
  } catch (err) {
    return json({ ok: false, error: String(err.message || err) });
  }
}
  • minimal: API key + handler allowlist + input validation (internal / low-risk)
  • standard: + timestamp/nonce replay prevention + AuditLog (writing ops data)
  • hardened: + HMAC signature + per-function ACL + rate limit (public / sensitive)

Deeper: CORS via simple request

Calling GAS from an external browser, default to text/plain;charset=utf-8 instead of application/json to avoid preflight. The server parses e.postData.contents directly and returns errors as a JSON body, not via HTTP status.

One line to keep: fix the executor, access scope, and auth before deploying: and never run a function name straight from the payload.

Frequently asked questions

What happens if you deploy Execute as Me to Anyone?
Anyone who visits can touch sheets and mail with the deployer's permissions. Without separate input validation and auth, the public endpoint is wide open to abuse or data leaks.
Does deploying to Anyone with a Google account expose your source code?
Yes. That option requires project sharing, so visitors can read your source. If closed source is a contract term, use Me + Anyone combined with your own app-level auth instead.
What is the minimum protection for a public doPost endpoint?
The minimal tier requires an API key, a handler allowlist, and input validation. Never dispatch a function name taken directly from the payload; only call allowlisted handlers.