← All privacy impact assessments
PIA: Signing in and keeping an account safe
Amended 27 October 2026: removing a lost phone from one screen. A member can remove their own lost phone in one step. That ends its sessions (and refuses them again for two hours), cancels its pending access and deliveries, deletes the earlier-message copies held for it, and starts a key change in each of their groups. The screen shows each step as done, pending or failed, and never says "complete" while one is unknown. It says plainly that messages and photos already on the phone stay readable on it while it's offline, and that changing the Group Password afterwards stops it opening new ones. Where the phone can't be told apart from the member's others, it says that their other phones will be signed out too.
Amended 27 October 2026: phones named by model. A phone added from this update on is named after its model, such as "iPhone 15 Pro" or "Pixel 8", so a member can tell their phones apart in Devices and keys. A phone added before takes its model's name once, if it still has the general name ("iPhone or iPad" or "Android device"); a name the member chose is never replaced. The name comes from the phone's model label and nothing else: no serial number, hardware or advertising identifier or build fingerprint, and never the name the member gave the phone in its own settings. If the app can't read the model, the phone keeps the general name. Other members of the member's groups can see these names, as they could already see the general one, and Devices and keys says so. The app shows a model name only in its owner's own list of phones; it isn't put in notifications, chat, our analytics or our error reports. The name stays with the phone's record for as long as that exists, and is deleted with the account.
Status: Built on 7 October 2026, not yet released. Written late: this assessment was written after the code, when a review pointed out that child accounts can reach these screens. It records the design as built and does not pretend to have come first. Written: 7 October 2026 · Last revised: 27 October 2026 (removing a lost phone from one screen; phones named by model) Nothing here is legal advice. Children's Code citations are to the exposure draft; section numbers may move on registration (due 10 Dec 2026).
1. Purpose and scope
Five ways for a member to keep their own account safe: set a new password or reset a forgotten one, turn on an optional second sign-in step using an authenticator app, lock the app on their phone with Face ID, a fingerprint or the phone's passcode, sign out every other device, and confirm their email address when they create an account. Since 9 October 2026, an adult can also change the email address on their account.
In scope: what each of these collects and where it goes, for every personal account, including child accounts. Out of scope: the shared display, whose account is not a person's and never reaches these screens (see shared-display.md), and Sign in with Google and Apple, assessed in sign-in-with-google-and-apple.md.
2. Data involved
| Kind | Whose | Children's? | Sensitive? | Free text? |
|---|---|---|---|---|
| A new password, sent once to our authentication provider, which stores only a one-way hash | The member's own | Yes, for a child account | No | Typed, never stored readable |
| An emailed one-time code, to reset a password, confirm an address, or confirm a password change | The member's own | Yes | No | No |
An authenticator secret (auth.mfa_factors), its name, and each verification attempt (auth.mfa_challenges, which records the IP address) |
The member's own | Yes | No | No |
| Whether the app lock is on, and after how long it asks, kept on the phone only | The member's own | Yes | No | No |
| The result of a Face ID, fingerprint or passcode check: yes or no | The member's own | Yes | Not collected. The phone's operating system does the check; the app receives only success or failure | No |
Whether the email address is confirmed (auth.users.email_confirmed_at) |
The member's own | Yes | No | No |
A new email address, while a change waits for its two codes (auth.users.email_change), then as the account's address |
The member's own | No: not offered under 18 | No | Typed |
Which sign-in added each of the member's phones (user_devices.session_id, bound_at), set by our server |
The member's own | Yes | No | No |
The phone's model name, such as "Pixel 8" (user_devices.name), read from the phone's model label when it is added. Shown in its owner's Devices and keys; other members of the owner's groups can read it. Kept for the phone record's lifetime, deleted with the account |
The member's own | Yes, for a child's phone | No | No |
A removed sign-in, kept for two hours so its leftover token is refused (auth_session_denials: the sign-in's id, the member's id, when), or for a phone added before binding, "sign-ins older than this moment, except this one" (auth_session_floors) |
The member's own | Yes | No | No |
Strictly necessary: each item exists only to let the member prove who they are, or to stop someone else using their account, or (a phone's model name) to let them tell their phones apart when they remove one. Nothing here is about the group, and only a phone's model name can be seen by another member.
Not collected, and could have been: a face, fingerprint or passcode; backup codes; the member's phone number for text-message codes; a list of the member's sign-ins and where they are (the sign-out removes them without listing them).
3. Flows and locations
| Data | Device | Our database (Supabase, Sydney) | Elsewhere |
|---|---|---|---|
| Password | Typed, sent once | Hash only | None |
| Emailed codes | Typed | Stored as a hash until used or expired | The email itself, sent by our authentication provider's email service. Which mail service delivers it in production is unverified in this assessment |
| Authenticator secret | Shown once as a QR code and setup key, then held in the member's own authenticator app | Stored by our authentication provider to check codes | None |
| App lock setting | Phone keychain, this device only, never in a backup | Not sent | None |
| Face ID, fingerprint or passcode | Checked by the phone's operating system | Not sent | None |
No model, no other group and no other member receives any of it.
4. Legal basis and consents
None of these features relies on a consent purpose. Each is something the member chooses to do for their own account, and can undo: turn two-step sign-in off, turn the app lock off, or set another password. Confirming an email address is part of creating an account, which the member agrees to under our terms.
5. Risks and mitigations
| Risk | Who is harmed | Mitigation | Structural or conventional? | Residual |
|---|---|---|---|---|
| Someone with a member's password signs in on another phone | The member and their group | Optional two-step sign-in: the app holds the new sign-in on a code screen, with no group loaded, nothing sent and no notification opened, until the code is entered | Conventional — the app enforces it; our database does not check the second step yet, so the password used directly against our server skips it | Accepted for now, see §8 |
| A borrowed, unlocked phone is used to change the password | The member | A password change on a sign-in older than a day needs an emailed code first | Structural — enforced by our authentication provider | Small |
| A member loses their authenticator and cannot sign in | The member, including a child | The setup key, shown once with advice to keep it safe; or our team removes the second step on request | Conventional — depends on our support | A request could come from someone pretending to be the member; we act only on a request from the account's own email address |
| Someone picks up an unlocked phone and opens the app | The member and their group | Optional app lock; the app is covered whenever it is not in front, and while the setting is being read at start-up; a failed read locks rather than opens | Conventional — a check in the app | A phone whose passcode has been removed opens without asking, so the person is never shut out |
| A phone that is lost stays signed in | The member and their group | Remove it in Devices (next row), or sign out everywhere else: the other phones stop within 15 minutes, when their sign-in next renews, and then clear their keys and offline data as any sign-out does | Structural — the renewal is refused by our authentication provider | Sign out everywhere else: up to 15 minutes of access; the copy says so |
| A removed phone keeps using its sign-in, or adds itself back as a new phone | The member and their group | Each phone is bound to the sign-in that added it, by our server, never by the app. Removing a phone (remove_device) ends that sign-in and records it as removed for two hours, so its leftover token is refused at once on every table, every server function, photos and live updates, and it cannot add a phone again. A phone added before binding has no recorded sign-in, so removing it signs out every other sign-in of the account and refuses their leftover tokens too; the phone doing the removing keeps working. Access tokens last 15 minutes (from 20 October 2026) |
Structural — database and our authentication provider. The app signs itself out at the first refusal | See §8 |
| A mistyped address at sign-up leaves an account no one can recover | The member | Email confirmation with a code before the account is used | Structural | None found |
| Someone holding an unlocked phone moves the account to their own address | The member and their group | Changing the email needs a code from the new address and one from the current one; the wall's account can never change | Structural — enforced by our authentication provider and a database trigger | Both codes are needed only while email confirmation is on in production; with it off, one code from either address is enough |
6. Structural versus conventional
- Structural: password hashing and minimum length; the emailed code before a password change
on an old sign-in; email confirmation; refusing to renew the other devices' sign-ins; binding each
phone to the sign-in that added it, and refusing a removed sign-in everywhere in the database
(
session_allowed(): the membership checks, a restrictive policy on every table, photos and live updates, and the check before every server request); the app lock setting never leaving the phone (the keychain setting excludes backups); biometric checks done by the operating system. - Conventional, test-pinned: the app's hold on a sign-in that still owes its second step (source checks that no group work runs at the root while it is owed); the app lock's cover while its setting is unknown; a failed read locking rather than opening.
- Conventional: recovery of a lost authenticator through our team.
7. Best interests of the child
A child account gets every one of these features, because each protects the child's own account and nothing in them is seen by anyone else. Two choices were weighed:
- The app lock can stop a parent opening the app on their child's phone. We allow it. A parent's oversight in this app comes through the group (the guardian features described in child-accounts.md), which the lock does not touch. Locking one's own app is a reasonable thing for a young person to want, and it protects them more often than it gets in a parent's way.
- A child who loses their authenticator could be locked out. The setup key and our team are the way back. Two-step sign-in is off unless the child, or someone with them, turns it on.
- Changing the account email is not offered under 18. A guardian asks help@groupapp.ai instead, and the screen says so. The address is how an adult in the group invited the child, and it is where the codes that protect the account go; we would rather an adult was involved in moving it. The database refuses the change if the young person asks for it themselves; we make it for them when a guardian asks.
What the child is told: the screens state plainly what each feature does, in the same words an adult sees.
8. Residual risk we accept
- Two-step sign-in is enforced by the app, not yet by our database. Someone with a member's password who calls our server directly, rather than using the app, is not asked for the code. End-to-end encrypted content still needs one of the member's own devices or their recovery phrase before it can be opened. Enforcing the step in the database is planned.
- Sign out everywhere else takes up to 15 minutes to reach another device, until its sign-in next renews; the copy says so. Removing a phone in Devices is the way to cut one off at once.
- The app lock is a check in the app, not a separate encryption of what the app stores.
- Removing a phone ends its sign-in; it does not reach into the phone. What
covers it, from the moment the removal is saved: every table, every server function, photos, live
updates and adding a phone again. Our assistant server and server functions check a member's
sign-in with the authentication provider first, and it refuses an ended sign-in. A test pins that
answer for both ways those paths ask, and a check fails any of them that stops asking or ignores
the answer.
What it does not cover:
- anything already on the removed phone stays there, including content it had already opened;
- a fresh sign-in on the same phone, with the account's password, is not banned: that is a new sign-in, and a stolen password is the risk two-step sign-in addresses;
- a voice grant is not tied to a phone or a sign-in: the five-minute voice tokens it mints carry no sign-in id, so a grant held by the removed phone keeps working until it is revoked;
- a phone added before binding, or one whose recorded sign-in has ended, is removed by signing out every other sign-in of the account, and only after a confirmation that says so: the database refuses to do it otherwise; a brand-new sign-in made in the same second as that removal is refused until its first renewal, about 15 minutes later.
- An app version from before 20 October 2026 can't remove a phone at all (accepted by the founder): its Devices screen asks the database to revoke the row directly, which is refused, so it says "Not removed" and nothing changes. It fails closed. The member updates the app, or removes the phone from another one that is up to date.
9. Review trigger
Re-read this when two-step sign-in starts being enforced by our database; when backup codes, text-message codes or a device list are added; or when the app lock starts protecting anything beyond the app's screens.
10. Checklist against exposure draft s 38(2) (verified 2026-09-08)
| s 38(2) | Requires | Answered in |
|---|---|---|
| (a) | nature, scope, context, flow and purposes | §§1–3 |
| (b) | why collection is strictly necessary | §2 |
| (c) | lawful and fair means | §4 |
| (d) | best interests of the child | §7 |
| (e) | how we comply with the Code and the Act | §4, §6 |
| (f) | risk of harm to children | §5 |
11. Sources
app/security.tsx,app/devices.tsx,constants/deviceRemoval.ts,app/auth/mfa.tsx,app/auth/code.tsx,app/auth/signup.tsx,components/AppLockGate.tsx,lib/accountSecurity.ts,constants/accountSecurity.ts.supabase/config.toml([auth],[auth.email],[auth.mfa.totp]) andsupabase/templates/.- Tests:
lib/__tests__/accountSecurity.test.ts,__tests__/app/layoutTwoStepHold.test.ts,components/__tests__/AppLockGate.test.tsx,__tests__/app/auth/mfa.test.tsx,__tests__/app/security.test.tsx,__tests__/app/devices.test.tsx,__tests__/sign_out_others.test.ts,__tests__/member_email_change.test.ts. supabase/migrations/20261009010034_member_email_change.sql.- Supabase Auth documentation on multi-factor authentication, password security and email templates (supabase.com/docs/guides/auth).