AcadBridge is a Bun + TypeScript monorepo for authenticating against Academia and fetching academic data through a clean API.
Note: This repository is backend-only. It provides the API and scraping logic. For the mobile/web wrapper, see the AcadWrap repository (separate).
- Session-based login and logout
- Attendance, marks, courses, user, calendar, and timetable scrapers
- Combined data endpoint for one-shot fetching
- Shared types and schemas across packages
- Bun-native testing and runtime support
bun install
bun test
bun run devgit clone https://github.com/Pranjal-SB/AcadBridge.git
cd AcadBridge
bun installStart the API server:
bun run devBuild the project:
bun run buildPOST /login— Authenticate with Academia credentialsDELETE /logout— End the current sessionGET /hello— Health checkGET /attendance— Fetch attendance dataGET /marks— Fetch marks and gradesGET /courses— Fetch enrolled coursesGET /user— Fetch user profileGET /calendar— Fetch academic calendarGET /timetable— Fetch class timetableGET /get— Fetch all data combined
packages/
├── types/ # Shared TypeScript types and Zod schemas
├── scraper/ # Login flow and data scrapers
└── api/ # Hono API server
Docs-only update (2026-04-09): This section documents the production hardening contract for AcadBridge. No runtime code or test changes are included in this update. These requirements are operational contracts for future implementation.
AcadBridge is designed for secure, multi-user, production hosting. The following operational requirements are enforced in production builds:
- On startup, the API server validates all required environment variables:
REDIS_URLSESSION_ENC_KEYALLOWED_ORIGINSPORT
- If any required variable is missing or invalid, the server fails fast and does not start.
- /login endpoint:
- Limited to 5 requests per minute per IP (burst up to 10).
- Authenticated endpoints (all endpoints requiring a valid sessionToken):
- Limited to 60 requests per minute per sessionToken (burst up to 120).
- Exceeding these limits returns HTTP 429 with a clear error message.
- Only Backend-for-Frontend (BFF) server-to-server integration is supported. Browsers must not call AcadBridge directly.
- CORS is locked down:
- Allowed origins are set via the
ALLOWED_ORIGINSenvironment variable (comma-separated). - In production, the default is empty (deny all origins).
- Allowed origins are set via the
- Any browser-originated request from an origin not in the allowlist is denied (no CORS headers).
- Every request is assigned a unique request ID, included in all logs and error responses.
- Logs are structured (JSON or equivalent) and redact sensitive values (no passwords or cookie contents are ever logged).
- Authentication failures and upstream errors are logged with request ID and minimal context only.
- Added/clarified explicit documentation for:
- Startup environment validation (fail fast if required env vars missing)
- /login rate limiting (5/min/IP, burst 10)
- Authenticated endpoint rate limiting (60/min/sessionToken, burst 120)
- BFF-only, locked-down CORS (via ALLOWED_ORIGINS, default deny)
- Request IDs and structured logs (with sensitive value redaction)
- No runtime code or test changes were made in this update.
The following environment variables are required for the AcadBridge API:
REDIS_URL: Upstash Redis connection string for session persistence.SESSION_ENC_KEY: A 32+ byte base64-encoded key used for encrypting session data at rest.ALLOWED_ORIGINS: Comma-separated list of allowed origins for CORS. Defaults to empty (deny all) in production.PORT: The port on which the API server listens.DATABASE_URL: (Optional) Supabase Postgres connection string. Provisioned for future accounts, billing, and audit logs.
The following environment variables are mirrored for the future AcadWrap repository:
ACADBRIDGE_API_BASE_URL: The internal or production URL of the AcadBridge API. Used server-side only by the AcadWrap BFF.NEXT_PUBLIC_APP_URL: The public URL of the AcadWrap application.ACADWRAP_REFRESH_TTL_SECONDS: (Optional) Cache TTL for academic data in the AcadWrap application.
Commercial Readiness: Supabase Postgres is provisioned now to support future multi-user features (accounts, billing, audit), even if the MVP primarily uses Redis for session state.
See ROADMAP.md for planned improvements including:
- OpenAPI/Swagger documentation
- Docker support
- TypeScript SDK
- CLI tool
- Create a branch
- Make focused changes
- Run
bun test - Open a pull request
-
Success:
{ "success": true, "sessionToken": "...", "cookies": ["JSESSIONID=...", ...] } -
Invalid credentials:
{ "success": false, "error": "Invalid credentials or unexpected response" } -
CAPTCHA required:
{ "success": false, "captchaRequired": true, "captchaData": { "digest": "...", "imageBase64": "..." }, "error": "CAPTCHA required" }
- Any endpoint that requires a session token (all except
/loginand/hello) returns errors in the following shape if the token is missing, invalid, or expired:or{ "error": "Missing X-CSRF-Token header", "tokenInvalid": true }{ "error": "Invalid or expired session token", "tokenInvalid": true } - The
tokenInvalid: truefield is always present for token errors, regardless of endpoint.
- Added explicit API contract section for
/loginand error handling, documenting all response shapes (success, invalid credentials, captcha required, tokenInvalid rule). - No runtime code or test changes were made; this is a documentation-only update.
MIT