Skip to content

Repository files navigation

Stanford SAML Full-Stack Hello World

A reference full-stack "hello world" that runs behind Stanford workgroup-based SAML authentication, deployable to AWS or GCP with Terraform.

  • Frontend: Next.js / React (containerized)
  • Backend: Python FastAPI (containerized)
  • Database: SQLite (on a persistent disk)
  • Auth: Shibboleth SP sidecar (Apache + mod_shib) → Stanford IdP, with workgroup authorization via eduPersonEntitlement

Docs at a glance:

Architecture

                         ┌─────────────────────────────────────────┐
   Browser ── HTTPS ────▶│  shibboleth  (Apache + mod_shib, :443)   │
   (Stanford login)      │  · terminates Stanford SAML              │
                         │  · enforces workgroup at the proxy       │
                         │  · injects trusted identity headers      │
                         └───────────────┬───────────────┬─────────┘
                                         │ /              │ /api
                                         ▼                ▼
                              ┌──────────────────┐  ┌──────────────────┐
                              │ frontend (Next.js│  │ backend (FastAPI) │
                              │  :3000)          │  │  :8000)           │
                              └──────────────────┘  └────────┬─────────┘
                                                             │
                                                     ┌───────▼────────┐
                                                     │ SQLite /data    │
                                                     │ (persistent disk)│
                                                     └─────────────────┘

The Shibboleth container passes X-Remote-User (SUNet ID) and X-Entitlement (workgroups) to the apps after stripping any client-supplied copies, so the backend can trust them. The backend re-checks workgroup membership on protected routes; the proxy also enforces it on that same route (/api/hello) when REQUIRED_WORKGROUP is set — every other route just requires a valid session.

Repository layout

frontend/     Next.js app + Dockerfile
backend/      FastAPI app (auth, SQLite) + Dockerfile
shibboleth/   Apache + mod_shib SP sidecar (shibboleth2.xml, attribute-map.xml)
dev/          Dev-only nginx that mocks the SP for local runs
deploy/       bootstrap.sh (cloud-agnostic first-boot provisioning)
terraform/aws Single EC2 VM + EIP + EBS data disk
terraform/gcp Single Compute Engine VM + static IP + persistent disk
docs/         AWS/GCP deployment guides + Stanford SPDB/Workgroup registration walkthrough

Quick start — local development (no Stanford IdP)

Requires Docker. A dev nginx injects mock identity headers so you can exercise the real auth/authz code path without a real IdP.

cp .env.example .env          # optional; dev has sane defaults
docker compose -f docker-compose.dev.yml up --build
open http://localhost:8080

You'll see the mock user, their workgroups, and an incrementing SQLite visit count. To test the 403 (non-member) path, run with a mismatched entitlement:

DEV_ENTITLEMENT="stanford:not-my-group" \
  docker compose -f docker-compose.dev.yml up --build

/api/hello will now deny access (the required workgroup isn't in the mock entitlements) while /api/me still shows the user.

Deploy to a cloud

Prereqs: Terraform ≥ 1.5; AWS or GCP credentials; a DNS name you control.

cd terraform/aws          # or terraform/gcp
cp terraform.tfvars.example terraform.tfvars
# edit: app_hostname, admin_ssh_public_keys, letsencrypt_email, required_workgroup, ...
terraform init
terraform apply

Then follow the outputs:

  1. Point your app_hostname DNS A record at the output public_ip.
  2. Re-apply with enable_letsencrypt = true for a real TLS cert.
  3. Register the SP in SPDB using the output sp_metadata_url — see docs/stanford-saml-registration.md.

Both stacks provision a single Ubuntu VM that installs Docker, mounts a dedicated persistent disk at /data (SQLite + SP keypair), obtains TLS, and runs docker compose up.

Endpoints

Route Auth Description
GET / Stanford session Hello page (user + workgroups + visit count)
GET /api/health none Liveness probe
GET /api/me Stanford session Authenticated identity + workgroups
GET /api/hello workgroup member Greeting; records a visit in SQLite
/Shibboleth.sso/* SP handlers (ACS, metadata, logout, session)

Notes & caveats

  • SQLite is single-writer. This design is intentionally one VM with the DB on a persistent disk — it does not scale horizontally. For multiple instances, move to Postgres (RDS / Cloud SQL); the backend uses SQLAlchemy so swapping DATABASE_URL is most of the work.
  • Trust boundary: only the Shibboleth proxy may set the identity headers. Apache strips inbound copies; never expose the backend port publicly.
  • State: Terraform state is local by default. For team use, configure a remote backend (S3 + DynamoDB, or a GCS bucket).
  • MFA / attribute release are governed by Stanford; see the Attribute Release Policy.

References

Getting help

Reach out to DARC: gsb_darcresearch@stanford.edu

About

Stanford SAML (workgroup) authenticated full-stack hello world — Next.js + FastAPI/SQLite behind a Shibboleth SP sidecar, Terraform for AWS + GCP

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages