flowss asks you to put work on a service — often unpublished work, sometimes work under embargo. This page explains, in plain terms, how your account and your work are protected: how you sign in and how to add two-step verification, how one account is kept apart from another, how keys are stored, what the browser is and is not allowed to do on our pages, how sharing and invitations are guarded, how abuse is limited, and how to report a vulnerability. It starts with what flowss does not have, because a list of strengths is only useful when you also know the gaps. For what we collect and how long we keep it, see Privacy and your data; for uptime, backups and support, see Reliability, status and support.
At a glance
| Topic | What to know |
|---|---|
| Certifications | None. flowss holds no SOC 2, ISO 27001 or other third-party certification and has not had an external penetration test. |
| Signing in | GitHub, Google, or email and password. Passwords must be at least 8 characters and breached passwords are refused. No magic-link sign-in. An emailed link opened in a different browser asks "Continue as ...?" before it signs anyone in. |
| Two-step verification | Optional, with any authenticator app (6-digit codes). Turn it on under Account → Security. Enforced by our servers, not just the sign-in page. |
| Your password | Never received or stored by flowss; it goes straight to the authentication service. Changing it signs out every other device and emails you. |
| Connection | HTTPS only, with a one-year Strict-Transport-Security policy. |
| Isolation between accounts | Row-level security on every user-facing table in the database, so a browser key can only ever reach its own account's rows. |
| Platform API keys | Shown once, stored only as a SHA-256 hash, revocable at any time. |
| Your own AI key | Kept in your browser by default; optionally saved to your account with AES-256-GCM encryption. Either way it passes through our server for each AI call. |
| In the browser | A content security policy, sanitising of untrusted diagram markup, and a locked-down sandbox for embeds. |
| Sharing | A share link contains the whole diagram — treat it as public. Project and team invitations ask you to confirm before you join. |
| Abuse limits | Daily limits per IP address, account or API key, reset at midnight UTC. |
| Security log | API-key and saved-key changes, plan and billing events are recorded; events you trigger carry your IP address and browser string. |
| Reporting a problem | Email hello@flowss.ai with the subject Security report. Acknowledgement within three working days. No bug bounty. |
Read this first: what flowss does not have
These are stated plainly so that nobody adopts flowss for a purpose it cannot yet carry.
| Gap | What it means for you |
|---|---|
| No SOC 2, ISO 27001 or any third-party security certification | None has been attempted. If your institution requires one to approve a tool, flowss does not clear that bar today. |
| No external penetration test, no bug bounty | The controls on this page were designed and reviewed in-house and are covered by automated tests. That is not the same as an adversary having tried. |
| No point-in-time recovery | Cloud sync is a convenience, not custody. Export anything you cannot afford to lose — see Exporting your work. |
| No HIPAA, FERPA or GDPR-processor commitments; no signed BAA or DPA | Do not put identifiable patient data, student records, or anything a data agreement governs into flowss. A custom DPA and security review are listed for Enterprise as "At GA" — not available today. |
| No uptime commitment or published SLA | The terms say so explicitly. See Reliability, status and support. |
| No single sign-on (SAML or Google/Microsoft SSO), SCIM, SIEM export or data residency yet | These appear on the pricing comparison for Enterprise marked "At GA". They do not exist today. |
| Self-service account deletion is paused | You can export your data at any time, but deletion currently goes through support. See Privacy and your data. |
Note: the full engineering detail behind these controls — encryption, the content security policy, the embed sandbox, rate limits and the service providers involved — is documented internally rather than published. Ask for it athello@flowss.aiand you will get an answer in writing. The vulnerability-reporting contact and safe-harbour commitments are public at/.well-known/security.txt.
Your account
Ways to sign in
You can sign in with Continue with GitHub, Continue with Google, or an email address and password. The GitHub and Google buttons appear only when that provider is switched on, so you never click a button that leads to an error. There is deliberately no "email me a sign-in link" option. Every step of creating an account and signing in is described in Creating an account and signing in; this section covers the security side.
| Protection | How it works |
|---|---|
| Your password never reaches flowss | The sign-in form sends your password directly to the authentication service. Our own code only ever sees the resulting session. GitHub and Google sign-in involve no flowss password at all. |
| Minimum length | 8 characters, enforced by the authentication service itself, so it cannot be skipped by bypassing the form. |
| Breached passwords refused | A password that has appeared in a known data breach is refused however long it is. |
| No composition rules | You are not forced to mix symbols and digits; length plus the breach check is what counts. Suggest strong password generates a random 16-character password for you. |
| Bot protection | When it is switched on, a short verification challenge (Cloudflare Turnstile) appears on sign-in, sign-up, Forgot password?, resending a confirmation link, and the password change form. It raises the cost of automated password guessing without a puzzle for people. Each challenge is single-use, so a retry needs a fresh one. |
| Neutral answers | Resend and reset requests never reveal whether an address has an account: the answer, and how long it takes, is the same either way. |
| Mail limits per address | Confirmation and password-reset emails are capped per address and per network each day, so nobody can flood your inbox or use up your allowance. The exact limits are in Creating an account and signing in. |
| Links bound to your browser | When you start a sign-up, a password reset or a GitHub or Google sign-in, your browser keeps a one-hour random token. A link that comes back to the same browser completes as normal. A link opened anywhere else (a second device, or a link someone forwarded to you) is never installed silently: a page titled "Continue as address?" explains "This link was opened in a different browser from the one that asked for it, so we check before signing you in." Choose the Continue as button (it names the address) only if you asked for that email yourself, or I didn't ask for this. For a reset link the page reads "Reset this account's password?" with Continue to set a new password. |
Two-step verification
Two-step verification adds a second question after your password, or after Google or GitHub: a 6-digit code from an authenticator app such as 1Password, Google Authenticator or Authy. Someone who learns your password — or gets into your inbox and resets it — still cannot get into your account without your phone or password manager.
To turn it on:
- Open your account page and scroll to Security (or go straight to /account#security).
- In the Two-step verification card, choose Turn on two-step verification.
- Scan the QR code with your authenticator app. If your app cannot scan, type the setup key printed beside it instead ("Can’t scan? Type this key into the app instead. Save it in your password manager too — it is how you get back in if you lose your phone."). The copy button next to the key (labelled "Copy the setup key" for screen readers) puts it on your clipboard.
- Type the 6-digit code your app now shows into Code from the app. Spaces are ignored.
- Choose Verify and turn on. The button stays disabled until you have entered six digits.
The card lists what happens next: "Your other devices are then signed out, and ask for a code when you sign in there." The browser you set it up in stays signed in and is upgraded immediately. Allow up to a minute for every other device to start asking for a code.
When it is on, the card shows On, the name of the authenticator entry (for example "Authenticator app (2026-10-04 09:30 UTC)") and the date it was added. In your authenticator app the entry is named flowss.
If you abandon setup, choose Cancel. An unfinished setup is cleaned up automatically the next time you start.
Tip: save the setup key in your password manager, or scan the QR code on a second device, before you choose Verify and turn on. The card's "If you lose your phone" note says the same: the setup key is how you get back in.
Signing in with two-step verification on
After your password (or GitHub or Google), you arrive at a page titled Enter your verification code, which names your account's email address and says it "has two-step verification on. Open your authenticator app and enter the 6-digit code it shows for flowss."
- Open your authenticator app and find the flowss entry.
- Type the current code into Verification code. Spaces are ignored.
- Choose Verify. You continue to wherever you were going.
Every way in leads to this step when the account has two-step verification on: the password form, GitHub and Google, the confirmation link and the emailed six-digit code. Until you enter a code, the rest of flowss treats the session as signed out. Sign in with a different account on that page signs this session out and returns you to /signin.
Turning two-step verification off
- Go to Account → Security.
- In the Two-step verification card, choose Turn off.
- Read the confirmation: "Turn off two-step verification? Your account will be protected by your password alone. Enter the code your authenticator app shows now to confirm it is you."
- Type the current code into Code from the app.
- Choose Turn off again (it stays disabled until six digits are entered), or Keep it on to back out.
Turning it off needs a fresh code from the authenticator, typed at that moment. A stolen password alone cannot switch it off, and neither can someone who finds a browser left signed in.
If you lose your authenticator app
flowss does not issue backup or recovery codes. The setup key you saved when you turned two-step verification on is the way back: add it to an authenticator app on any device and it produces the same codes. Store the entry in an app that backs up or syncs (most password managers do).
The challenge page says: "Lost your phone? If you saved the setup key when you turned this on, add it to an authenticator app on any device and enter the code it shows. Lost the key too? Email hello@flowss.ai from the address on your account." The account page's "If you lose your phone" note adds: "Proving an account is yours without the code takes time, so keep the key safe."
Changing your password
The Password card under Account → Security changes your password the honest way — by asking for the current one.
- Enter Current password.
- Enter New password (at least 8 characters) and Confirm new password.
- If two-step verification is on, enter Code from your authenticator app. If it is not shown and the account needs a code, the form asks for it after your first attempt.
- Complete the verification challenge if one appears.
- Choose Change password.
On success you see "Password changed. Other devices have been signed out." Every other signed-in session on the account is ended, this browser stays signed in, and a "password changed" notice is emailed to the account address (at most one such notice an hour). Your current password is checked by the authentication service directly, on a separate short-lived connection, so a wrong guess does not disturb your session and the password is never seen by our servers. The Change password button stays disabled until all three password fields are filled in.
Tip: if you signed up with GitHub or Google and never set a password, the form will say your current password is incorrect. Use Forgot password? on the sign-in page to create one instead.
The password-reset page that an emailed reset link opens is for recovery only: it accepts a session that came from a reset link or code within the last fifteen minutes. If you are already signed in and visit it any other way, you are sent to Account → Security, where the current password is required.
Sessions and signing out
- You stay signed in on a browser until you sign out, the session expires or you clear the site's data. Sessions are refreshed automatically as you move around.
- Session cookies are marked Secure on HTTPS (so they are only sent over an encrypted connection) and SameSite=Lax.
- Sign out (the account menu in any studio, or the sign-out icon beside your name) clears this device's personalisation, any AI key you kept in this browser, and the cached plan and points of the account. Your documents are left untouched. Because the AI key is read from browser storage for every request, other open flowss tabs in the same browser stop sending it too.
- An AI key kept in the browser is tied to the account that saved it. If a different account signs in on that browser, the key is cleared rather than handed to the new account.
- A password change signs out every other device. That is the fastest way to end sessions you do not recognise.
Warning: on a shared or lab computer, always sign out when you finish. A session left open on a shared machine stays open.
Account emails that alert you
| When it is sent | |
|---|---|
| Password changed | Whenever your password is changed, by reset or from Account → Security (at most one notice an hour) |
| Confirm your email, Password reset | Only when someone asks for one, and limited per address each day. Both carry a one-time link and a code. The confirmation email ends "We will never ask you for your password or for this link."; the reset email ends "Do not send your password, reset link or verification code." |
If you receive a password-changed notice you did not expect, reset your password at once, turn on two-step verification, and email hello@flowss.ai. Treat any message that asks you for your password or for a sign-in link as phishing.
How your data is protected
In transit
Every page and API call is served over HTTPS. A one-year Strict-Transport-Security policy (eligible for browser preload lists) means that after your first visit your browser refuses to talk to flowss over plain HTTP at all, so a network attacker has nothing to downgrade. Pages also ask the browser to upgrade any insecure sub-request.
Isolation between accounts
Every user-facing table in the flowss database has row-level security switched on, with rules that scope each row to the account (or project, team or class) it belongs to. The two kinds of key a browser can ever hold — the public key every visitor's browser has, and a signed-in user's session — can therefore only reach the rows they are entitled to, whatever a modified client asks for. A leaked session token reaches that one account's rows and nobody else's.
Tables that only the service itself should touch — the security log, telemetry, error reports, feedback and similar — have row-level security on with no access rule at all, which is the strictest setting: no browser key can read or write them.
One honest qualification: our own server code connects to the database with a privileged service connection, which is not subject to those rules, and scopes each query to the signed-in caller in its own code. Row-level security is therefore the floor under a compromised or modified browser, not a safety net under our own server code. That privileged credential is used only on the server and is never sent to a browser.
Platform API keys
API keys you create on your account page (they start glyp_) let CI pipelines and other tools call the headless render API and the REST API.
| Property | Detail |
|---|---|
| Generation | 24 random bytes, shown to you exactly once under "New key — copy now, won’t show again" |
| Storage | Only a SHA-256 hash is stored, plus the first 10 characters so you can recognise the key in the list |
| Recovery | Impossible by design. If you lose a key, revoke it and create another |
| Revocation | Immediate. The confirmation reads "Revoke this key? Existing integrations using it will stop working immediately." |
| Last used | Each successful use stamps a last-used time you can see in the list |
| Names | Up to 80 characters; "Untitled" if you leave the name blank |
Requests that authenticate with an API key (in an Authorization: Bearer header or an X-Api-Key header) are exempt from the cross-site check described below, because a browser never attaches such a header on its own. API keys are not tied to a plan: any signed-in account can create them. See The REST API and Embedding and the render API.
Your own AI provider key
On Starter and above you can bring your own key from any of the eight supported providers. There are two ways to hold it, and they differ:
| Mode | Where the key lives | What our server does with it |
|---|---|---|
| In your browser (the default; Settings → Bring your own API key in a studio) | Your browser's local storage | Receives it with each AI request, holds it in memory for that one request, uses it to call your provider, and never writes it to a database or log |
| Saved to your account (Bring-your-own key on the account page, Save key) | Encrypted in our database with AES-256-GCM | Decrypts it in memory per request, only to call your provider. The encryption key lives only in the server environment, never in the database, so a copy of the database alone does not reveal your key |
In both modes the provider call is made from our server, so the key does pass through it — "browser-only" bring-your-own-key is not something flowss claims. Only the first 8 characters of a saved key are kept readable, so the settings can show which key is saved. Crash reports are scrubbed for anything that looks like a credential before they are written, because some providers quote a key back in an error message. A key shaped like no supported provider's is refused before it is sent anywhere, with "That doesn't look like an API key from a supported provider. Nothing was sent." See Bring your own AI key.
Where your work travels
| Situation | What leaves your browser |
|---|---|
| You are signed in | Your whole workspace syncs to our database about a second after each edit, every 20 seconds and when you leave the page. There is no opt-out. See Cloud sync, offline work and devices. |
| You use an AI feature | The prompt and the relevant part of the diagram go to the AI provider for that one call. Automatic repair, which is on by default, also sends a diagram that fails to render; turn it off in Settings → Personalization & privacy → Repair broken diagrams automatically. |
| You render PlantUML or one of the Kroki-backed engines | The diagram source is relayed by our server to that render service. Every other engine draws in your browser or on our own server, although a document can still ask your browser to fetch something it names, such as a protein structure id or a chart's data file. |
| You search for online icons | The words you type, and the id of each online icon you preview or place, are relayed by our server to Iconify. No diagram content goes with them, and Iconify sees our address rather than yours. |
| You share or embed | The link itself contains the compressed diagram, so it reaches our servers each time it is opened. |
The full list of who receives what is in Privacy and your data.
Protections in your browser
A diagram tool renders code, and that is also its main risk: a shared link, an embed or an AI answer can carry markup that wants to run as script. flowss defends against that in layers.
Response headers
Every page and API response carries these headers. You can check them yourself in your browser's network panel.
| Header | Value | What it does for you |
|---|---|---|
| Strict-Transport-Security | max-age=31536000; includeSubDomains; preload | HTTPS only, for a year, on every subdomain |
| Content-Security-Policy | Starts default-src 'self' and includes object-src 'none', base-uri 'self', form-action 'self' | Nothing loads from anywhere not explicitly allowed; no plugin objects; an injected base tag cannot redirect links; forms cannot post off-site |
| X-Content-Type-Options | nosniff | A file that lies about its type is not treated as script |
| Referrer-Policy | strict-origin-when-cross-origin | A link out of flowss reveals only our site name, never the page path |
| Permissions-Policy | camera=(self), microphone=(self), payment=(self), with geolocation, USB and motion sensors off | Only flowss itself may ask for the camera (photo import), microphone (dictation and live rooms) and payment (checkout), and each still needs your browser permission. Nothing embedded in a page may ask |
| X-Frame-Options | SAMEORIGIN (except embeds) | Other sites cannot frame flowss pages to trick your clicks |
| Cross-Origin-Opener-Policy | same-origin-allow-popups | Cuts the link to cross-origin windows while keeping payment and sign-in pop-ups working |
| Cross-Origin-Resource-Policy | same-origin | Another site cannot pull our pages and API responses into its own page as images, scripts or other sub-resources |
Static files such as fonts, images and the editor's code carry a smaller baseline set: Strict-Transport-Security, nosniff and the referrer policy.
The content security policy also limits where images may load from to an explicit list (flowss itself, the two sign-in avatar hosts, our file storage and two icon and asset hosts) rather than any HTTPS address, because image requests are the classic way an injected script exfiltrates data.
Untrusted diagram markup is cleaned
Diagram output is inserted into the page as markup, and the source that produced it is often not yours — share links, project links, embed links and AI answers all arrive from outside. Before any of it reaches the page it passes through a sanitiser that removes script tags, every event-handler attribute and script-bearing links, and also strips form controls (forms, inputs, buttons, text areas and drop-downs), while keeping the drawing itself (gradients, styles, text labels) intact. Every link left in a diagram opens without giving the destination a handle on your flowss tab or a referrer. Mermaid diagrams run in Mermaid's own strict mode, which sanitises its output and disables script links in click handlers.
Embeds are sandboxed
The embed viewer is the one page any website may frame, and it renders whatever diagram the embed link carries. It is therefore loaded into a browser sandbox that grants only scripts and pop-ups. Without same-origin access the embedded page cannot read cookies or local storage and cannot make signed-in requests, so even a successful injection lands somewhere with nothing worth stealing.
| Never granted to an embed | Why |
|---|---|
| Same-origin access | It would give the embed your storage and session |
| Top navigation | An embedded diagram must not redirect the page hosting it |
| Forms | Nothing in an embed submits, and a form is a phishing tool |
| Modal dialogs | An alert or prompt from an embed is only ever abuse |
| Pointer lock and downloads | Not needed to show a diagram; exporting happens in the studio |
See Embedding and the render API.
Cross-site request protection
Changes made with your signed-in session — saving, inviting, creating keys, billing actions — check that the request genuinely came from a flowss page (its Origin header, or its Referer when there is no Origin). A request forged from another website is refused with "Cross-site request blocked." A change that arrives with neither header is refused too. Requests authenticated by an API key, or carrying your own AI key, are exempt, because a browser never sends such a header by itself.
Server-side fetches
When the server fetches something on your behalf, it is restricted so that a crafted document cannot make it reach systems it should not. A picture referenced inside an SVG that the server rasterises for an export is refused if it points at a private, loopback, internal or cloud-metadata address, and the connection is pinned to the address that was checked, so a changed DNS answer cannot slip past. Files that the server reads from a code repository (for diagrams kept in step with a repository) may only come from a short list of public code hosts — GitHub, GitLab, Bitbucket and Codeberg — over HTTPS. Redirects are followed by hand, at most three, and a redirect off that list is refused.
Sharing, invitations and live sessions
| Feature | How it is guarded |
|---|---|
| Share links | The link contains the whole diagram. We do not keep a copy, index it, or record who opened it — but anyone holding the link holds the diagram. Treat a share link as public once sent. |
| Project invitations | Opening an invite link never joins you automatically. A card asks "Join project as you?", names the role you would have (for example "You'd join as an editor."), and warns that joining shows your name and your email address to everyone on the project and opens it in your studio: "Only join projects you recognise — nothing happens until you choose." Choose Join project or Not now. If you are already a member, the card says "This invite would not change anything" and offers Dismiss and Open project. |
| Team invitations | The same: "Join team as a member?" (or "as an admin?") with "Joining shares your name and email address with everyone on this team. Only join teams you recognise — nothing happens until you choose." Choose Join team or Not now. |
| Team invite links | Owners and admins see every live link under Live invite links — "Anyone holding one of these URLs can join this team. Withdraw a link you shared by mistake, or one that has been passed on." — and can withdraw any of them. Removing a member also withdraws the team's shared links (removing an admin withdraws the admin-role links), so the person removed cannot rejoin through one; a fresh link takes one click. If the links cannot be withdrawn, the removal is not made: "Couldn't withdraw this team's invite links just now, so nothing was changed. Try again in a moment." If you are already on the team, the invite card says so and offers Open team. |
| Live sessions started from a share link | The room link is the key: anyone holding it can join. If a room link leaks, leave the session and start a new one; the new room's address cannot be guessed. |
| Live sessions in private projects | Not available: "Live presence, voice and screen sharing are temporarily unavailable in private projects. Saved projects and comments still work." |
Roles and permissions are described in Sharing and permissions, Teams and organisations and Live collaboration.
Abuse protection and rate limits
Costly or abusable operations have daily limits that reset at midnight UTC. Each limit is tuned to what the operation costs rather than one global number, and each counts the right thing:
| Counted per | Examples |
|---|---|
| Account | Hosted AI when you are signed in, AI requests and agent runs on your own key, account export, joining classes, invitations you send, support requests |
| API key owner | Calls to the render and REST APIs made with an API key — one allowance across all of an account's keys |
| Email address and network | Confirmation and password-reset emails, and invitation emails to any one address |
| IP address | Anything with nobody to name, such as feedback, anonymous usage events, and icon searches that miss the cache |
Some limits rise with your plan — hosted AI, server-side exports, TikZ conversion, PlantUML and Kroki rendering, and Evidence literature search. The rest are the same on every plan. Requests on your own AI key are not metered in points, but they still count against a separate daily abuse ceiling, set above every plan's hosted limit, and agent runs on your own key have a lower ceiling of their own inside it. Hosted AI also has a platform-wide daily safety limit, so a hosted call can occasionally be refused for a reason that is nobody's quota.
For the limits that guard against password-guessing and real spend — sign-in emails, account operations and hosted AI — an unreachable limit counter means the request is refused rather than allowed through, with "We couldn't check the request limits just now, so we haven't run this. Nothing has been charged — please try again in a moment." Other limits fall back to a local counter during such an outage rather than failing. Every limit message you can meet is listed in Reliability, status and support, and AI limits in AI points and limits.
The security log
flowss keeps an append-only security log of account and billing events, so that "was that me?" can be answered if an account is ever questioned and billing disputes can be resolved.
| Recorded | Not recorded |
|---|---|
| API key creation and revocation | Sign-in and sign-out (the authentication service keeps its own log) |
| Saving or deleting a stored AI key | The content of your diagrams |
| Plan changes, AI-point top-ups and reversals, refunds, disputes and failed payments | Anything used for analytics or advertising |
| Joining a waitlist, and an account deletion |
An event that came from a request you made records your IP address and browser user-agent string; an event that came from our payment provider records your account and no IP address. Apart from the daily rate-limit counters, which are keyed by IP address and expire at midnight UTC, this is the one place flowss keeps an IP address. No key a browser holds can read or write the log.
Reporting a vulnerability
If you find a security problem, please tell us before you tell anyone else.
- Email
hello@flowss.aiwith the subject Security report — or use the Security card on the contact page, which opens an email with the subject already filled in. - Include the affected page, the steps to reproduce, and what you observed. Do not include other people's data.
- Do not use the flowss Support Agent on /support for this. It deliberately routes anything mentioning a vulnerability or breach to a person and sends nothing to the AI provider.
The same address and commitments are published in machine-readable form at /.well-known/security.txt.
| We commit to | Detail |
|---|---|
| Acknowledgement | Within three working days |
| Assessment | Our intended fix, or our reasons for declining, within fourteen days |
| Credit | In our release notes on the blog, if you would like it |
Safe harbour. We will not pursue or support legal action against research conducted in good faith under this policy: test only against accounts you own, do not access or modify other people's data, do not degrade the service for others, stop as soon as you have proof, and give us a reasonable window before disclosing.
Note: there is no bug bounty and no payment for reports. We say so here so nobody learns it after the work is done.
Tips
- Turn on two-step verification, and keep the authenticator entry in an app that backs up. There are no recovery codes.
- Use Suggest strong password or a password manager; a long random password plus the breach check is stronger than any composition rule.
- Sign in with the same method every time, and sign out on shared computers.
- Give every API key a name that says where it is used ("CI pipeline", "docs build"), so you know which one to revoke.
- Keep your own AI key in the browser unless you need it on several devices; saving it to your account is convenient but means an encrypted copy lives in our database.
- Never paste passwords, one-time codes, API keys or payment details into a support request, the help box or a feedback message.
- Treat every share link and embed link as public. For private work, invite named people into a project instead.
- Only join projects and teams you recognise; joining shows your name and email to the other members.
Limits and known constraints
- No third-party certification, external penetration test or bug bounty (see the table at the top).
- No backup or recovery codes for two-step verification. The account page sets up one authenticator app and has no option to add a second; to use the same codes on another device, add the saved setup key there.
- Two-step verification uses authenticator-app codes only: no text-message codes and no security keys.
- No single sign-on, SCIM, audit-log export or data residency options today.
- No in-app way to change the email address on an account; contact support. (To add a password to an account you created with GitHub or Google, use Forgot password? on the sign-in page.)
- The content security policy has to allow inline scripts and runtime code evaluation on most pages, because several diagram engines and the code editor need them. The pages that complete a sign-in and the two-step verification page run a stricter policy without runtime code evaluation. The sanitiser and the embed sandbox exist precisely because the policy alone cannot carry the defence.
- Our server code uses a privileged database connection and scopes queries in code; row-level security protects against a compromised browser, not against a bug in our own server.
- Your own AI key passes through our server on every AI request, in both storage modes.
- PlantUML and the Kroki-backed engines send diagram source to an outside render service when they draw.
- Live rooms started from a share link are open to anyone who has the link.
- Sign-up email is limited by the authentication service and the verification challenge, not by our own per-address counters.
- Two-step verification takes up to about a minute to reach devices that were already signed in.
Troubleshooting
| What you see | What it means | What to do |
|---|---|---|
| "That code didn’t match. Codes change every 30 seconds — enter the one your app shows now." | The code was wrong or had just rolled over | Wait for a fresh code and enter it promptly; check your phone's clock is set automatically |
| "That took too long. Enter the current code from your app." | The verification step expired | Enter the code your app shows now |
| "Too many attempts. Wait a few minutes, then try again." | Several wrong codes or passwords in a row | Wait a few minutes before trying again |
| "Enter the 6-digit code from your authenticator app." | The code field is empty or not six digits, or the account needs a code | Type all six digits; spaces are ignored |
| "This account has no authenticator app set up." | The challenge page found no verified authenticator | Choose Sign in with a different account and sign in again; contact support if it repeats |
| "Confirm a code from your authenticator app first, then try again." | The action needs a session that has presented a code | Sign in again and complete the code step |
| "Two-step verification isn’t available on this deployment yet." | The feature is not switched on for this service | Contact support |
| "Couldn’t load your security settings. Check your connection and refresh." | The Security card could not reach the authentication service | Check your connection and reload the page |
| "Couldn’t start two-step setup. Check your connection and try again." or "Couldn’t turn two-step verification off. Check your connection and try again." | The request to the authentication service failed | Reconnect and repeat the step |
| "Couldn’t check that code. Check your connection and try again." | The code could not be sent for checking | Reconnect, then enter the code your app shows now |
| "Sign-in isn’t available. Refresh the page and try again." | The page could not reach the sign-in service | Refresh the page |
| "This account has no email address to sign in with." | The password form needs an email-based account | Contact support |
| "Your current password is incorrect. If you sign in with Google or GitHub and never set a password, use “Forgot password?” on the sign-in page to create one." | Wrong current password, or no password was ever set | Re-type it, or create a password with Forgot password? |
| "The two new passwords don’t match." | New and confirm fields differ | Re-type both |
| "That password was refused as too weak or previously leaked in a data breach. Choose a different one of at least 8 characters." | The new password failed the length or breach check | Choose another, or use a generated password |
| "That is your current password. Choose a new one." | New password equals the old one | Pick a different password |
| "Complete the verification challenge first." | The bot-protection challenge is unfinished or expired | Complete it again; each attempt needs a fresh one |
| "Cross-site request blocked." | A change was submitted from outside a flowss page, or a privacy extension stripped the request's origin | Make the change from the flowss page itself; if it persists, allow flowss in the extension |
| "That doesn't look like an API key from a supported provider. Nothing was sent." | A pasted AI key has the wrong shape | Copy the full key again from your provider's dashboard |
| "Revoke this key? Existing integrations using it will stop working immediately." | Confirmation before revoking an API key | Confirm only once integrations have a replacement key |
| "Could not open the invite." or "Could not accept the invite." | The invite could not be opened or accepted (for example, the link was withdrawn or has expired) | Ask the person who invited you for a fresh link |
| "Continue as address?" after opening an emailed link | The link was opened in a different browser from the one that asked for it | Continue only if you requested that email yourself; otherwise choose I didn't ask for this |
| "Couldn't withdraw this team's invite links just now, so nothing was changed. Try again in a moment." | Removing a member needs the team's shared links withdrawn first, and that failed | Try the removal again shortly |
| "Live presence, voice and screen sharing are temporarily unavailable in private projects. Saved projects and comments still work." | Live rooms are not offered inside private projects | Collaborate through the saved project and comments |
