Phase's sample environment file ships three working 64-character secrets
Secrets management for teams and AI agents.
At a glance
- What is it?
- An open-core secrets manager with a Python backend, a Next frontend and five compose variants, where password sign-in is off by default but every container image is tagged with a floating tag. The most consequential line in the repository is the sample secret file.
- Who is it for?
- Phase is worth evaluating for a team that already treats secrets as infrastructure, because the defaults lean the right way in the places that usually go wrong: password authentication is refused unless you enable it, database migrations run as a job the backend waits on, and only the reverse proxy publishes ports. Two things to fix before any deployment reaches a real network.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 4, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The sample environment file ships three working secrets
The sample configuration file is well made in every respect except one, and that one exception matters more than the rest of it.
Three secrets are pre-filled with complete sixty-four character hexadecimal strings: the authentication signing secret, the application secret key, and a server secret. There is a warning directly above them telling you to replace them with cryptographically strong random values, and a suggestion of the exact command to generate one. So the intent is unambiguous and the values are placeholders.
The problem is that they are indistinguishable from real values. Nothing marks them as fake. A reader who copies the file, fills in the host and protocol, and deploys has a secrets manager whose signing keys are published in a public repository, and nothing in the running system will say so.
The file is otherwise careful about posture. It opens with a pointer to the configuration reference for the complete list of settings, and it carries its own warning that production deployments should use a more secure method than an environment file to store secrets. That is the right advice for a file that ships keys in it, and it is also an argument for not shipping keys in it.
Rotating those three values is the first thing to do after any deployment from the sample, and doing it before first traffic rather than after is much cheaper.
Signup is open to every email domain unless you uncomment one
There are two authentication defaults here and they point in opposite directions.
The permissive one is the email domain whitelist. The setting exists, documented as a comma-separated list of domains users are allowed to sign in with, and it is shipped commented out, with a note that leaving it commented allows all domains. On a service whose entire purpose is holding credentials for a team, an open signup path is the first thing to close, and closing it requires editing a commented line rather than uncommenting one.
The careful one is password authentication, and it is genuinely well done. Password login is opt-in rather than default. By default the behaviour is single sign-on only: every password endpoint, which the file enumerates as registration, login, change-password and password-based recovery, is refused outright, and the login page hides the password UI rather than showing a form that will fail.
Refusing the endpoints instead of merely hiding the form is the part worth copying into other projects. A hidden form is a UI decision that an API client bypasses in one line; a refused endpoint is an actual control.
Social sign-in providers are enabled by listing them, and the example shows three comma-separated names, so enabling the feature is also a matter of uncommenting one line.
Every container image carries a floating tag
The compose file at the repository root builds the reverse proxy locally but pulls the other services by name, and the names all end the same way. The frontend image, the backend image used for the migration job, and the backend image used for the service are all referenced with a floating latest tag and no digest.
That matters here more than it would in most projects, because the release cadence is fast. Three recent releases sit within about two weeks of each other: a minor bump, another minor bump, and a patch. If you deploy on a Friday and your orchestrator restarts on a Monday, the tag may resolve to a build you have never tested against your configuration.
The pattern is also inconsistent within one file. The reverse proxy is built from a local Dockerfile, which is reproducible, while the two images that actually contain the application logic are pulled by a moving name.
The fix is unglamorous and worth doing anyway: pin all three to a release tag, or to a digest, and treat a tag bump as a change requiring your own test pass.
The other thing this file gets right is ordering. It does not simply start everything and hope.
The backend waits for migrations to finish successfully
There is a separate one-shot service whose entire job is to apply database migrations, and the application service declares a dependency on it that requires successful completion rather than mere startup.
That is the correct shape and it is rarer than it should be. The usual arrangement starts the application and the migration job together and hopes the application retries, which produces a startup error on a fresh database and a race on an existing one. Here the application waits, and if the migration fails, the application never starts.
The dependencies are also graded rather than flat. The database is waited on with a health check, so the container has to report itself healthy, while the cache is only waited on until it has started. That distinction is correct, since a cache that is briefly unreachable at boot does not corrupt anything, and a database that is not ready to accept a connection does.
Two more details are worth noting for anyone adapting this file. The application service is also told that migrations happen externally, which tells it not to run them itself, and both the migration job and the application carry the same host, origin and cookie-domain settings derived from a single host variable, so the session cookie and the allowed-host list cannot drift apart between the two processes.
The frontend reaches the backend on two different paths
The frontend service is configured with two backend addresses, and the difference between them is the interesting part.
One points at the backend service directly on the internal port, and is used for calls made on the server side, which in a Next application means anything during render or in a route handler. The other points at the public host with a path prefix, and is exposed to the browser as a public variable, so it is used for calls made from client components.
The consequence is that half the traffic to the backend bypasses the reverse proxy and half of it goes through it. Server-side calls stay inside the container network, which is faster and which means they do not get the proxy's TLS termination or any request size limits configured there. Client-side calls get the full public path, prefix included.
That split is a deliberate consequence of how a Next application is split, and getting it wrong is a common source of two-hour debugging sessions where a request works in a handler and fails in a component. It is worth reading both variables together before changing either.
The authentication base URL is derived from the same host and protocol pair as the cookie domain and the allowed-origin list, which keeps the sign-in callback and the session cookie pointing at the same origin.
Four compose files and one private network
The repository root carries four orchestration files rather than one: a production compose file, a development one, a staging one, and one for running the whole stack over a private network tunnel, with a matching directory of configuration for it.
Four variants of a security product's deployment is a lot of surface to keep in step, and it is the place to look first when asking whether a fix has landed everywhere.
The production file itself is disciplined about exposure. A single service publishes ports, and it is the reverse proxy, which is built from a Dockerfile in the repository rather than pulled, with its configuration mounted read-only from a file in the tree. Everything else, the frontend, the backend, the migration job, the worker, the database and the cache, joins one private network and publishes nothing. The service names are fixed, which is convenient for log searching and unfortunate if you run two stacks on one host.
The worker service has its own container name, and the migration job reuses the backend image with a different command, which is a sensible way to keep two roles on one build rather than maintaining two images.
MIT, with one directory carved out
The licensing is stated in one sentence and the sentence has an exception in it. The repository is available under the MIT expat licence, with the exception of a directory whose contents are the Pro and Enterprise features, which require a licence from the vendor. The model is described as open-core and is compared to GitLab's.
That is a conventional arrangement and the readme is upfront about it, which is more than most. Worth noting for anyone deciding whether they can build on it: the community code is permissive, and the features that matter for a commercial deployment may not be. The directory is a separate top-level path, so you can tell from a checkout which side of the line a given file is on without reading the headers.
The metadata for the project records no licence name, so the file and the readme are the only sources, and the readme is the one that carries the exception. If you need certainty, ask.
The security reporting guidance is the other thing to take from this file, and it is correct. Vulnerabilities are not to be filed on the public issue tracker or discussed on the public forum, because those are public. A separate security document in the repository and a separate documentation page on how the encryption works are the two pointers offered instead.
Editorial conclusion
Phase is worth evaluating for a team that already treats secrets as infrastructure, because the defaults lean the right way in the places that usually go wrong: password authentication is refused unless you enable it, database migrations run as a job the backend waits on, and only the reverse proxy publishes ports. Two things to fix before any deployment reaches a real network. The sample environment file contains three fully formed secret values, so if you copy it without regenerating every line you are running a secrets manager with publicly known signing keys. And sign-in is open to any email domain unless you set a whitelist, which on a service holding credentials is the difference between an invite-only tool and a public one. Finally, every image in the compose file carries a floating tag, so pin versions deliberately or your next restart silently upgrades you.
Frequently asked questions
What is Phase?
An open-core secrets management product for teams and AI agents, with a community edition published under the MIT expat licence and Pro or Enterprise features kept in a separate directory that requires a vendor licence. The model is described as open-core and compared to GitLab's.
Does Phase allow password sign-in by default?
No. Password authentication is opt-in. By default all password endpoints, including registration, login, change-password and password-based recovery, are refused and the login page hides the password form. Setting the option to true enables password signup and login, and social sign-in providers are enabled by listing them in the configuration.
How do I self-host Phase?
With the compose file at the repository root, which brings up a reverse proxy, a frontend, a backend, a one-shot migration job, a worker, a database and a cache on one private network, with only the proxy publishing ports. Configuration goes in an environment file created from the sample, and the full reference for settings lives in the documentation.
How should I report a security problem in Phase?
Not through the public issue tracker and not on the public forum, because both are public. The repository points to its own security document and to a documentation page explaining how the encryption works. Contribution in general goes through the contributing guide and the project chat server.
What should I change before deploying Phase in production?
Regenerate the three secrets in the sample environment file, which ship as complete placeholder values and are not marked as placeholders. Set the email domain whitelist, which is commented out by default and allows every domain when left that way. Treat the floating image tags as a decision to pin, since the project ships releases every few days.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/phasehq-console)