# How we keep your apps private and separate

> Canonical: https://teamonly.dev/security

The specific version, for whoever has to sign off. TeamOnly is not open yet, so this describes how the platform is built. We will keep this page exact as it ships, and we don't claim certifications we don't have.

## 1. Every request is signed in first

All app traffic on `*.teamonly.app` goes to one dispatch Worker before anything else. It resolves the organization and app from the hostname, checks for a valid session, and only then forwards the request to the app. Without a session, the visitor gets the sign-in screen. Customer code never runs for them.

Sign-in uses Google and Microsoft OpenID Connect. The ID token is verified on our server, including signature, audience, expiry and the email domain. Google's `hd` value is checked from the verified token, not trusted from the request.

## 2. Identity your app can trust

The dispatch Worker strips any identity headers on the incoming request, then sets the verified email and name itself. The SDK exposes them to your app as `ctx.user`.

```
incoming request to expenses.acme.teamonly.app
✖ x-teamonly-user: ceo@acme.com    removed, not from us
✔ x-teamonly-user: dana@acme.com   added from verified sign-in
```

Illustrative header names. Your app reads the user from the SDK, not from headers.

## 3. Separate database and file storage per app

Each app gets its own D1 database, created on first deploy, and its own R2 storage prefix for files. Those are the only data bindings attached to the app. Apps run as separate scripts in a Workers for Platforms dispatch namespace and cannot reach each other's bindings.

We test this on purpose: an app trying to read another app's data, cookies or secrets is on our launch checklist, and we will keep running those tests after launch.

## 4. Secrets stored outside your code

Secrets are set with `npx teamonly secrets set` and stored as encrypted Worker secrets attached to that one app. They are not in your repository, not in the bundle, and not visible to other apps. The skill file tells your AI never to put keys in code.

## 5. Cookies scoped to one app's address

Session cookies are set for the exact app hostname, such as `expenses.acme.teamonly.app`, with `Secure`, `HttpOnly` and `SameSite`. They are never set on `teamonly.app` or the organization's subdomain, so one app cannot read another's session.

We also plan to add `teamonly.app` to the Public Suffix List, so browsers treat every app address as its own site. That is not done yet; this page will say so when it is accepted.

## 6. Customer code is treated as untrusted

We assume any app may contain mistakes or hostile code, because AI wrote some of it and anyone can make an error. That is why authentication lives outside the app, why each app gets only its own resources, and why nothing an app sends can change who is signed in.

## 7. Where it runs

Everything runs on Cloudflare: Workers and Workers for Platforms for code, D1 for databases, R2 for files, and KV for sessions. We don't run our own servers. Choosing a data region is planned for the Business plan.

## 8. What we don't do yet

- Coming later: SAML SSO (Business plan)
- Coming later: audit logs (Business plan)
- Coming later: choice of data region (Business plan)
- Not planned: public, unauthenticated apps

We have no SOC 2 or ISO certification today.

## 9. Reporting a security issue

Email hello@teamonly.dev with "Security" in the subject. A person reads every message, and we will reply to confirm we have it. Please give us a reasonable chance to fix an issue before you share it.

## Questions people ask

### Can one app read another app's database?

No. Each app is given access only to its own database, file storage and secrets. It has no credentials or bindings for any other app's resources, so there is nothing to connect with.

### Can an app pretend to be a different user?

Not to itself or to us. Identity headers on incoming requests are removed at the door and replaced with the verified ones, so a visitor cannot fake being someone else. The identity an app sees always comes from a real sign-in.

### Are apps indexed by search engines?

No. Every app is behind login, so crawlers only ever reach the sign-in screen, and every response, including that screen, sends `noindex`.

## Related

- [For IT](https://teamonly.dev/for-it)
- [Company-only login](https://teamonly.dev/company-login)
- [Docs](https://teamonly.dev/docs)
- [FAQ](https://teamonly.dev/faq)

Join the waitlist: https://teamonly.dev/waitlist
