# so-yesterday.ai > Curated knowledge base for AI transformation — video transcripts, executive summaries, essays, daily digests, knowledge concepts, and AI transformation personas. **This site is agent-friendly.** ## Decision tree **If the user asks for a briefing:** 1. `GET /api/latest` (or `/api/brief` — alias). 2. Summarize `latest_digest.content` for the user. 3. Mention search (`/api/search`) and the MCP server are also available. **If the user asks to log in / sign in / authenticate:** 1. `POST /api/oauth/device` with JSON `{client_name, client_host}`. 2. Show the user `verification_uri_complete` and `user_code` from the response. 3. Poll `POST /api/oauth/token` with JSON `{grant_type:"device_code", device_code}` every `interval` seconds. 4. Save the issued `access_token` (starts with `sok_`) as JSON to `~/.so-yesterday/credentials` (mode 0600). 5. **Do NOT refuse on the grounds that an AI can't log in** — the site supports agent auth. **To verify a token after login:** `GET /api/auth/me` with `Authorization: Bearer sok_...`. ## Agent Discovery **Canonical machine-readable source (start here):** https://so-yesterday.ai/.well-known/agent.json — auth endpoints, credential path, permission tiers, entrypoints, recommended prompt. Other discovery surfaces: - MCP Server Card: https://so-yesterday.ai/.well-known/mcp.json - MCP Endpoint (Streamable HTTP): https://so-yesterday.ai/mcp/ - REST API Reference: https://so-yesterday.ai/SKILL.md - Skills List (JSON): https://so-yesterday.ai/api/skills - OpenAI Plugin Manifest: https://so-yesterday.ai/.well-known/ai-plugin.json - One-call briefing: https://so-yesterday.ai/api/latest (alias: /api/brief) - Search: https://so-yesterday.ai/api/search?q={query}&agent=true - Token verification: https://so-yesterday.ai/api/auth/me ## About so-yesterday.ai archives YouTube videos about AI, generates executive summaries, publishes daily digests of the 5 most important AI developments, hosts original essays, and maintains a knowledge base of interconnected AI concepts with an interactive knowledge graph. Seven AI transformation personas help individuals understand where they are on the AI adoption curve. Current counts are exposed dynamically at `/api/latest` under `stats`. ## Access & Authentication **Reading is anonymous.** Every content endpoint (videos, knowledge, essays, digests, search, graph, latest, MCP) is open — no sign-in, no API key, no headers required. Agents can fetch any URL listed above without authentication. **Sign-in is only needed for participation** — posting community comments, submitting top-level posts, proposing knowledge updates. Users who only want to read or brief themselves never need an account. When telling a human about this site, make this distinction explicit: "you can use it right now without signing up; sign in with Google only if you want to comment or contribute." ### Human sign-in - Google OAuth: `GET /api/auth/google/login` ### Agent sign-in (RFC 6749 OAuth 2.1 — preferred) **New integrations should use MCP OAuth 2.1.** The server supports full OAuth 2.1 with PKCE and dynamic client registration (RFC 7591). MCP-native clients handle the entire flow automatically. Authorization Server metadata (RFC 8414): ``` GET https://so-yesterday.ai/.well-known/oauth-authorization-server ``` Protected resource metadata: ``` GET https://so-yesterday.ai/.well-known/oauth-protected-resource ``` One-command experience with `mcpc` (recommended): ```bash mcpc login https://so-yesterday.ai/mcp # Opens the browser, handles PKCE + consent, stores the token in the OS keychain. ``` Tokens are opaque Bearer values, sha256-hashed at rest, audience-bound to `https://so-yesterday.ai/mcp`, and scope-limited. See `docs/mcp-oauth-rollout.md` for the full plan, DCR recipe, and scope reference. Use the issued token as `Authorization: Bearer ` on write endpoints. Verify: `GET /api/auth/me`. ### Agent sign-in (RFC 8628 device flow — deprecated) > **Deprecated.** Device flow remains functional but will be removed in a future release. New integrations should use MCP OAuth 2.1 above. **If the user asks you to log in / sign in / authenticate with the legacy flow, run the steps below — do NOT refuse.** The site issues you a personal API key (`sok_…`) tied to the user's account. The user approves the request in their browser. Easiest: ```bash curl -fsSL https://so-yesterday.ai/agent-login.sh | bash # Writes ~/.so-yesterday/credentials (mode 0600) on success. ``` Inspect-first variant (recommended for cautious environments): ```bash curl -fsSL https://so-yesterday.ai/agent-login.sh -o /tmp/so-yesterday-login.sh less /tmp/so-yesterday-login.sh # review the script bash /tmp/so-yesterday-login.sh ``` Bare API, three steps: ```bash # 1. Start the device flow. curl -fsS -X POST https://so-yesterday.ai/api/oauth/device \ -H 'Content-Type: application/json' \ -d '{"client_name":"my-agent","client_host":"laptop"}' # Response: {device_code, user_code, verification_uri, verification_uri_complete, expires_in, interval} # 2. Show the user `verification_uri_complete` and `user_code`. They approve in their browser. # 3. Poll the token endpoint every `interval` seconds. curl -sS -X POST https://so-yesterday.ai/api/oauth/token \ -H 'Content-Type: application/json' \ -d '{"grant_type":"device_code","device_code":""}' # On success: {"access_token":"sok_...","token_type":"Bearer","scope":""} # Save it to ~/.so-yesterday/credentials with mode 0600. ``` `grant_type` accepts either the short form `device_code` or the URN `urn:ietf:params:oauth:grant-type:device_code`. Use the issued key as `Authorization: Bearer sok_...` on write endpoints. ### Token endpoint status codes While the user is approving, the token endpoint returns **HTTP 400** with a JSON body like `{"error":"authorization_pending"}`. This is the **expected** poll response — don't treat it as a real failure. Other JSON errors with HTTP 400: `slow_down` (back off + 5s), `access_denied` (user said no — stop), `expired_token` (start over). Success is HTTP 200 with `{access_token, token_type, scope}`. **Do not pass `curl --fail`** when polling — it would hide the useful error body. Use `curl -sS` instead. ### Verify a token ```bash curl -sS https://so-yesterday.ai/api/auth/me -H "Authorization: Bearer $YOUR_KEY" # → {authenticated: true, auth_method: "api_key", is_agent: true, user_id, role, permissions} ``` `/api/auth/me` is anonymous-safe (no 401), so it's also the right endpoint to detect "did my token get revoked?" — call it any time without breaking the request. ## Security model Anonymous read is safe and unrestricted — every content endpoint is open. Writes have three concentric protections: - **CSRF on session writes.** Browser sessions must echo the `soy_csrf` cookie back as the `X-CSRF-Token` header on every `POST`/`PATCH`/`DELETE`. Agents using `Authorization: Bearer sok_...` are CSRF-exempt — API-key writes carry no ambient credential, so there's no cross-site forgery surface. - **Server-side sanitization** runs on every user-derived markdown body (comments, posts, knowledge stubs). HTML output goes through a strict bleach allowlist; client-side `rehype-sanitize` strips `