Skip to content

Add auth on games #87

Description

@Exeloo

Which app is this feature request for?

other (involves client, website and possibly server)

Feature

The loader has no access control. Anyone who can reach the client URL can load the game:

  • The client's /manifest, /env and /game/* routes (apps/client/src/server.ts) are public and have no authentication.
  • The website (apps/website) fetches the manifest and downloads every game file into OPFS without identifying the user.
  • The game server (apps/server) forks the game's main.js and never learns who the connecting players are.

This means developers can't:

  • limit a game to certain users (closed beta, paid access, internal testers)
  • reuse an existing identity provider (Google, GitHub, Discord, Keycloak, a studio's own SSO, etc.)
  • get a trusted user identity inside the game or on the game server

The goal is to add an optional authentication step to the loader, configured by the developer. It should check the user through SSO / OAuth2 before any game file is served, and deny access to everyone else.

Ideal solution or implementation

Support OpenID Connect / OAuth2 (Authorization Code + PKCE) with any provider, configured through CLI options or environment variables. When nothing is configured, behavior stays exactly as it is today.

client

  1. Add new options, for example:
    --auth-issuer <url>          OIDC issuer (discovery via /.well-known/openid-configuration)
    --auth-client-id <id>
    --auth-client-secret <secret> (optional, confidential clients)
    --auth-scopes <scopes>        default: "openid profile email"
    --auth-allow <rule>           allowed emails / domains / groups / roles claim
    
    Custom (non-OIDC) OAuth2 providers could be supported by setting the authorize, token and userinfo URLs explicitly.
  2. Add auth routes: /auth/login (redirects to the provider), /auth/callback (exchanges the code, validates the ID token), /auth/logout, and /auth/me.
  3. Store the session in an HttpOnly, Secure, SameSite cookie (signed or encrypted).
  4. Protect /manifest, /env and /game/*. Without a valid session, or if the user doesn't match --auth-allow, return 401 or 403. Serving the website shell (/, static assets) can stay public so it can show a login screen.
  5. Validate access rules on the server side (claims, email domain, group or role membership). Also provide a hook for custom rules, e.g. a function exported from the game directory or a webhook.

website

  1. When /manifest or /env returns 401, show a "Sign in" screen that redirects to /auth/login. On 403, show an "Access denied" screen.
  2. Make the authenticated user's identity (id, name, email, claims) available to the game, e.g. through IGameOptions or next to the env.
  3. Clear or scope the OPFS game cache on logout, so files downloaded by one user aren't reused by another user on the same browser.

server (follow-up, or part of this issue)

  • Pass a short-lived access token or ID token from the website to the game server when it connects, and provide a helper that checks it against the same issuer (JWKS). That way the game server can trust player identities.

Alternative solutions or implementations

  • Basic auth or a shared access key (--password, NANOFORGE_ACCESS_KEY): very easy to build, and enough for private previews. But there are no per-user identities, and revoking one person's access isn't possible.
  • Delegating auth to a reverse proxy (oauth2-proxy, Cloudflare Access, Authelia): works today with no code changes. But it has to be set up outside NanoForge, and the game never receives the user's identity. It would still help to document it as the "no built-in auth" option.
  • Custom SSO only through a plugin/hook API: the loader would call a function supplied by the developer to authorize each request. It's flexible, but every developer would have to write their own OAuth flow.

Other context

  • Relevant files: apps/client/src/server.ts (routes), apps/client/src/env.ts, apps/website/src/manifest.ts, apps/website/src/env.ts, apps/website/src/cache/cache.ts, apps/website/src/types/game.type.ts, apps/server/src/server.ts.
  • Security points to handle: the state and nonce parameters, PKCE, checking the token signature against JWKS, the redirect URI allowlist, and keeping client secrets out of /env. /env currently exposes every NANOFORGE_* variable, so auth secrets must use a different prefix or be filtered out.
  • Auth should require HTTPS in production. The client already supports --cert / --key.
  • This relates to the cache issue: with per-file hashing, the cached game files still have to be scoped per user or invalidated when the user changes.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions