Warning This is intentionally limited infrastructure. Do not use for production auth. Bugfixes accepted. Feature PRs will be closed.
Keep randoms out of your app. No auth. No database.
Sheet Gate is a tiny access gate for Netlify apps when full authentication is overkill. It uses Google Sheets as both the backend and the admin UI.
Give users an invite code. They get access. You stay in control.
Use Sheet Gate for:
- Demos
- Betas
- Internal tools
- Client previews
- "Please don't share this link" situations
- Not authentication
- Not user management
- Not production-grade security
This is polite gating, not Fort Knox.
Use Sheet Gate when:
- You just need to keep random people out
- You're shipping a demo, beta, or internal tool
- You don't want to manage users, passwords, or OAuth
- You're fine with "good enough" security
Use Auth0 / Netlify Identity when:
- You need real user accounts
- You care about password resets, MFA, roles
- You're building a production customer-facing app
This solves a different problem.
- Invite codes with expiration
- Device binding (discourages sharing)
- Usage logging
- HttpOnly cookies
- Google Sheets = database and admin UI
Answer these in order. Stop as soon as you hit a "no".
Do you just want to keep random people out of a link? → Yes → continue → No → don't use this
Is this for a demo, beta, internal tool, or client preview? → Yes → continue → No → don't use this
Are invite codes "good enough" instead of real user accounts? → Yes → continue → No → don't use this
Are you OK with "polite" security rather than Fort Knox? → Yes → continue → No → don't use this
Do you want something you can set up in minutes and delete later? → Yes → you should use this → No → you probably want a real auth system
TL;DR: If you're deciding between this and Auth0, you probably don't need this. If you're tired of setting up auth just to show something, this is for you.
This exists to remove friction, not to add guarantees.
If this section didn't disqualify you, jump to Quick Start. Everything else is reference.
┌──────────────┐
│ User App │
│ (Browser) │
└──────┬───────┘
│ enters invite code
▼
┌────────────────────────┐
│ Netlify Function │
│ access-verify │
│ │
│ - hashes code │
│ - checks expiration │
│ - checks device │
└──────┬─────────────────┘
│ read / write
▼
┌────────────────────────┐
│ Google Sheets │
│ (database + admin UI) │
│ │
│ Access tab: │
│ - code_hash │
│ - expires_at │
│ - device_hash │
│ │
│ Usage tab: │
│ - timestamp │
│ - event │
│ - path │
└──────┬─────────────────┘
│ success
▼
┌────────────────────────┐
│ HttpOnly Cookie │
│ │
│ - short-lived JWT │
│ - device-bound │
└──────┬─────────────────┘
│ subsequent requests
▼
┌────────────────────────┐
│ Netlify Function │
│ access-me │
│ │
│ - validates cookie │
│ - allows or blocks │
└────────────────────────┘
No database. No user accounts. No dashboards to build. Google Sheets is both the data store and the admin UI.
Using Google Sheets is not a shortcut. It's a deliberate design choice.
Sheets gives you things you'd otherwise have to build:
- A UI everyone already knows
- Permissions and access control
- Audit history
- Easy edits, revokes, and notes
- Zero schema migrations
For this use case, a traditional database adds more overhead than value.
What Sheets is good at here:
- Low write volume
- Human-in-the-loop administration
- Transparency over abstraction
- "I just need to see what's going on"
What Sheets is not good at:
- High concurrency
- Large-scale user systems
- Real-time guarantees
That's fine, because Sheet Gate is not trying to solve those problems.
If you need durability, scale, or strong guarantees, you should be using a real authentication system and a real database.
If you just want to keep random people out, Sheets is the right tool.
The fastest admin UI is the one you don't have to build.
- Node.js 18+
- Netlify CLI (
npm install -g netlify-cli) - A Google Cloud service account with Sheets API enabled
git clone https://github.com/BrettsRepo/sheet-gate.git
cd sheet-gate
npm installCreate a new Google Spreadsheet with two tabs:
Tab: Access (headers in row 1)
code_hash | label | expires_at | revoked | device_hash | max_devices | shared | first_seen_at | last_seen_at | notes
Tab: Usage (headers in row 1)
ts | event | label | code_hash | device_hash | path | meta_json
Share the sheet with your service account email (Editor access).
Copy .env.example to .env and fill in:
GOOGLE_SPREADSHEET_ID_FROM_URL=your-sheet-id
GOOGLE_SERVICE_ACCOUNT_EMAIL=your-service@project.iam.gserviceaccount.com
GOOGLE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n..."
ACCESS_PEPPER=random-secret-string-for-hashing
JWT_SECRET=another-random-secret-for-tokensnode scripts/test-connection.jsThis verifies your environment variables and Google Sheets access.
node scripts/generate-code.js "Demo User" "2025-12-31"This outputs a code and adds the hash to your Access sheet.
See SCHEMA.md for additional options: word-based codes, shared codes, device limits.
Option A: With Netlify CLI
netlify devVisit http://localhost:8888 and enter your access code.
Option B: Standalone (no Netlify CLI)
node server.jsVisit http://localhost:3003 - backend API only. Connect your frontend app to this endpoint.
| Document | Description |
|---|---|
| ARCHITECTURE.md | System design and data flow |
| SETUP.md | Detailed setup instructions |
| API.md | Endpoint reference |
| SECURITY.md | Security model and hardening |
| SCHEMA.md | Google Sheets schema reference |
| DEVELOPMENT.md | Local development guide |
| TROUBLESHOOTING.md | Common issues and solutions |
This project includes built-in security safeguards:
npm run test:run # Run all tests including security checks
npm run check-secrets # Scan for accidentally committed secrets
npm run precommit # Run before committing (secrets + tests)See SECURITY.md for the full security model and hardening checklist.
sheet-gate/
├── functions/
│ ├── _lib/ # Shared helpers + tests
│ │ ├── cookies.js
│ │ ├── cookies.test.js
│ │ ├── crypto.js
│ │ ├── crypto.test.js
│ │ ├── jwt.js
│ │ ├── jwt.test.js
│ │ ├── rateLimit.js # Rate limiting for brute-force protection
│ │ ├── rateLimit.test.js
│ │ ├── security.test.js # Security verification tests
│ │ └── sheets.js
│ ├── access-verify/ # POST - Verify code, set session
│ ├── access-me/ # GET - Check current session
│ └── access-log/ # POST - Log usage events
├── public/ # Static frontend
│ └── index.html # Gate UI
├── scripts/
│ ├── generate-code.js # Code generation utility
│ ├── check-secrets.js # Secret scanner
│ └── test-connection.js # Verify Google Sheets setup
├── docs/ # Documentation
├── server.js # Local dev server (standalone, no Netlify CLI)
├── netlify.toml
├── package.json
└── .env.example
Forked from swyxio/netlify-google-spreadsheet-demo - a proven pattern for Netlify Functions + Google Sheets integration.
MIT