No description
- TypeScript 92.2%
- C++ 5.6%
- Python 2.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
The completion code's `code?` input let a caller choose it; app.ts used that to make handoff.attemptId become the code verbatim, which is the account-takeover primitive Soul's probes proved. The store now always mints the code itself. attemptId survives only as a separate correlation field (StoredAuthCompletion.attemptId / CreateAuthCompletionInput.attemptId), and a new consumeAuthCompletionByAttempt(appSlug, attemptId, at) lets a caller that already knows the attempt handle (the private command plane) redeem the completion it created without ever touching the code. Also deletes HeimdallStore.registerApp: the runtime app-registration HTTP surface that minted it is already gone from this branch, and nothing else in the codebase writes to registered_apps (it sits empty on the live host). findRegisteredApp/listRegisteredApps stay: AppSlug is a plain string (contracts.ts), so registered_apps remains the real extension point for a slug Heimdall was never rebuilt to know about; a row is now provisioned by direct SQL, or InMemoryStore.seedRegisteredApp in tests, not by any app-facing writer. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
| .voidbot/state | ||
| assets | ||
| deployment/idunn | ||
| docs | ||
| notes | ||
| plugins/gamecult.heimdall.access | ||
| schemas | ||
| src | ||
| state | ||
| tests | ||
| tools | ||
| vendor | ||
| .env.example | ||
| .gitignore | ||
| .gitmodules | ||
| AGENTS.md | ||
| CLAUDE.md | ||
| LICENSE | ||
| package.json | ||
| pnpm-lock.yaml | ||
| README.md | ||
| tsconfig.json | ||
| vitest.config.ts | ||
Heimdall
Heimdall is the shared auth authority taking shape for GameCult-hosted experiments.
The point is painfully simple:
- stop rebuilding Discord/Patreon login glue in every app
- keep provider OAuth, linked identities, grants, entitlements, and session issuance in one place
- let app runtimes verify signed claims locally so "shared auth" does not become "everything phones home for every request"
- keep app-domain data separate so "shared auth" does not become "shared swamp"
Current Shape
This repo now has a stateful first slice instead of a decorative skeleton.
Landed right now:
- a TypeScript/Fastify service scaffold under
src/ - Ed25519 JWT signing plus
/.well-known/jwks.json - file-backed signing-key loading/bootstrap so restart does not vaporize the service identity when you configure a real key path
- signed OAuth start-state scaffolding for Discord, Patreon, GitHub, Twitch, YouTube, and Spotify
- durable auth/control-plane storage with in-memory and Postgres backends
- account, linked-identity, session, persistent OAuth attempt, grant, entitlement snapshot, and audit persistence
- a real Discord OAuth callback path for the first Repixelizer access flow
- direct backend callback handoff for same-host or Yggdrasil-reachable app backends
- AES-256-GCM sealing for managed provider tokens at rest
- a one-time browser completion exchange kept as fallback for opener
postMessagehandoff - app profile surfaces for Repixelizer, StreamPixels, and Spotiverse
- signed claim issuance for app-local verification experiments
- a local verifier helper in
src/verifier.tsso app backends can validate Heimdall JWTs without phoning home on every guarded request - a read-only Odin/Eve provider advertisement export that names redacted CultCache witness document shapes and paths without touching live secrets
- a daemon-owned CultCache boundary witness at
GC_ACCESS_CULTCACHE_PATHcontaining the Heimdall provider advertisement, command boundary, transport profile, and Idunn daemon-health summary - optional Idunn daemon-health publication over
cultnet.transport.rudp.v0whenGC_ACCESS_IDUNN_RUDP_HEALTHis configured - the
gamecult.heimdall.accessEve plugin with executabledescribe,validate, andprojectoperations plus a browser reference adapter - a loopback-only CultNet operation boundary on port
4101for authenticatedheimdall.auth.beginandheimdall.auth.complete; app payloads and completion claims are AES-256-GCM wrapped and HMAC-bound to expiry, nonce, operation, runtime, and idempotency identity - redacted provider, command-boundary, plugin, and transport records published through Odin under unique typed catalog keys; secret-bearing auth state never enters the catalog
- the deployed Ghostlight Eve host consumes that discovered boundary and keeps routine app-session verification local
Remaining work:
- the two-account and eight-account Ghostlight human canaries
- refresh/revocation flows and admin surfaces
- broader admin and inspection projections beyond the redacted access boundary
Canonical docs:
docs/architecture.mddocs/implementation-plan.mddocs/service-contract.mddocs/verse-service-contract.mddocs/app-profiles/repixelizer.mddocs/app-profiles/streampixels.mddocs/app-profiles/spotiverse.mdstate/map.yamlnotes/fresh-workspace-handoff.md
Dev Commands
pnpm install
pnpm dev
pnpm test
pnpm build
pnpm export:provider-advertisement
Working Loop
- Rehydrate from canonical state.
- Keep identity authority central and app-domain data local.
- Prefer a Yggdrasil-hosted shared service over duplicated per-app provider stacks.
- Let app backends verify signed claims locally instead of begging Heimdall on every guarded route.
- Commit finished passes before the notes start breeding.