DEV Community

flisk
flisk

Posted on

local-jwt Is Not an Identity Provider

Flisk is kind to a new service. That kindness is the bug.

A scaffolded backend, read from the files flisk project and flisk resource generated in Flisk 1.3.86, boots with a working login, a working database, a working URL, and a migration that already ran. A real application and a staging environment were not part of that reading. If your code treats those conveniences as the world, it will pass every local test and fail the first time it meets an identity provider.

The scope note says this plainly. Local is the intended use. CI can be a throwaway copy of local. Staging and production are out of scope. There is no command that deploys, exports a chart, or writes cluster config.

The harness, line by line

These are not opinions. They were read from the generated Compose file and .env of that scaffolded backend. Check them against your own tree before you quote them in a design doc.

What your app sees What Flisk actually gave it What production will not give it
NODE_ENV=development Set in the container. TDK_ENV comes from TILT_ENV, default development Your flags, including a real production
A JWT that verifies AUTH_MODE=local-jwt, signed with a JWT_SECRET generated per project in .env Your identity provider and key management
Postgres on a name you can guess One shared Postgres 16 container. One database per stack, named <project>_<stack>. Password from .env. Data in a Docker volume A managed database, backups, and a migrator that runs once
Tables already exist Services may migrate at container start. AUTO_MIGRATE is the escape hatch. flisk doctor warns about it A one-shot job, not "every replica migrates on boot"
http://api.shop.localhost/... Traefik on *.localhost, host ports 80 and 443 when free, otherwise a port from 8080–8180 and 8443–8543 Your ingress, DNS, and certificates
Secrets that are just there Git-ignored .env, or Infisical if TDK_SECRET_PROVIDER=infisical Your secret store
It fits Scaffolded backend limits: 512 MB and 0.5 CPU, with 256 MB and 0.2 CPU reserved Replicas, real limits, autoscaling
Unhealthy means curl failed Generated services get a Compose health check that runs curl inside the image. A bring-your-own service gets no Compose health check. Traefik's own check still applies. That was read in compose.star, not executed Your readiness and liveness probes

HTTPS is the line to be careful with. Traefik has an HTTPS entry point. How certificates are handled was not checked. Do not write "Flisk does local TLS" in a security review.

Three strings that must never land in source

The failure is not that Flisk uses them. The failure is an agent, or a tired human, pasting them into the application because the request succeeded.

*.localhost is a route, not a domain your frontend may hardcode. tdk up prints the URL. On Linux and WSL2 a non-root user cannot check port 80, so the fallback range is used and the printed URL includes a port. An agent that writes http://api.shop.localhost/api/orders into a client has coupled the product to one machine's port luck. A resource named orders-api is served at /api/orders because a trailing -api is dropped. That rule is also a Flisk rule. Read the base URL from the environment.

<project>_<stack> is a local database name. The next stack on that same Postgres container gets its own database, which feels like isolation and is not a production topology. One volume holds the data. flisk down keeps the project networks unless you pass --prune-networks. So "I reset the stack" often means "I stopped containers and left the network sitting there." If your seed assumes a fresh network or a fresh volume, it will pass on a new laptop and fail on the laptop that has been up since Tuesday.

local-jwt plus a project-local JWT_SECRET is a dev login. It is not a tenant model, not a rotation story, and not something another service should accept outside this Compose file. The alternative Flisk offers is an identity service when you add one. Add one before you demo auth to anyone who will ask where the keys live.

AUTO_MIGRATE on boot is the same shape of bug. It makes the first hour painless and makes "two replicas started together" a coin flip. Doctor warns. The warning is not a migration runner.

CI is allowed to be this fake. Staging is not.

The repository's own quickstart workflow runs a real flisk up on a GitHub-hosted runner. That is a throwaway environment, which is a fair use. A copy-paste workflow for your own repository lives in the CI docs, and its flisk up job had not been run on GitHub when the scope page was written. Do not treat an unread recipe as evidence that your pipeline already does this.

A green CI job against NODE_ENV=development and local JWT does not answer the production question. The scope note's own remedy is small:

  • Run the image your CI built, through a bring-your-own resource, at least once.
  • Read hosts, database names, and auth settings from the environment. Do not branch on "we are on *.localhost."
  • Test any NODE_ENV-dependent behavior in a run that is not Flisk.

Bring-your-own narrows the gap. It does not make the laptop a cluster. Flisk still will not generate the Helm values. The port, the image, and the health path will exist in service.json and again in the chart. Nothing syncs them. Changing one is a review of the other, every time.

A review checklist that fits in a pull request

Reject the diff if application code contains any of these:

  • localhost as a service address, including api.<stack>.localhost
  • the stack database name, or a password read from a comment instead of the environment
  • AUTH_MODE, JWT_SECRET, or a token signed for local JWT
  • a migration invoked because the process started, with no separate migrator
  • a health check that assumes curl exists in an image you did not build
  • a copy of .autogenerated/ or .tdk/.tdk-out/ pasted into a chart

Then ask one question the laptop cannot answer: what happens when this process starts twice, against a database it is not allowed to create, on a host it has never heard of?

If the answer is "Flisk handles that," the feature is still a local convenience. Ship the other behavior.

The size of the kindness

Flisk should keep being kind. A new service should get a URL, a database, and a token that verifies. The application does not get to remember how that kindness was implemented.

Local is a harness. The moment the harness is in source, you no longer have a service. You have a demo that only boots in the room where it was written.

Top comments (0)