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 as | Meaning | Watch out |
|---|---|---|
| Me (deployer) | Always runs with deployer’s permissions | Wrong for apps needing per-user separation |
| User accessing | Runs with the visitor’s permissions | Needs 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.