Skip to main content
Add OAuth pieces to a collection’s auth.signIn array to let users sign in through a provider. FrogBot matches the local user by email, or creates one when the collection’s create access allows it, and issues that collection’s session.

Enable Google sign-in

Install the identity-only Google piece:
Save this as collections/Users.ts and add Users to your root collections. createGoogle() accepts these options: The Google piece requests openid, https://www.googleapis.com/auth/userinfo.email, and https://www.googleapis.com/auth/userinfo.profile. It has no product actions or product scopes. Its account lookup uses Google’s userinfo endpoint and only supplies account.email for a provider-verified email. The admin login page automatically renders methods from the collection selected by admin.user. With multiple auth collections, set admin.user explicitly. You can reuse the same Google instance in another collection’s auth.signIn; each collection has its own routes and local users.

The first user

While the admin user collection has no users, the admin sends everyone to /admin/create-first-user. With sign-in methods configured, that page shows the sign-in buttons below the password form, so the first person can also continue with Google. The first person to finish either one becomes the first user. With the OAuth-only setup, the admin shows the login page instead, and the first person to sign in becomes the first user. On an empty deployed app, that can be anyone who opens the URL. Sign in yourself before you share it.

Register the callback

For the example above, register this redirect URI in your Google OAuth app:
For sign-in, :piece is the configured instance’s slug, which defaults to the piece slug. Unknown methods return 404. Callback origins use serverURL when configured, otherwise the request origin. Replace /api with your configured routes.api in requests and registered redirect URIs. A custom login page can link to the start endpoint:
returnTo must resolve to the same origin as the callback. Without it, the admin user collection returns to routes.admin; other collections return to /. OAuth state expires after ten minutes, is bound to the initiating browser and exact login route, and can be used only once. PKCE is used when the piece recipe sets pkce: true.

Identity and local verification

Every login matches by email within the target collection. Provider account IDs and connection rows are not login identifiers. FrogBot trims and lowercases the provider email, validates its format, and requires an unambiguous local match. For piece authors, oauth.account({ tokens, client, req }) returns { id, label, email? }. Only return email when the provider has verified that identity. Omit it or reject the lookup when verification cannot be established. Core validates the email’s format; the recipe is responsible for proving provider verification. A missing email cannot sign a user in. User creation runs collection validation and hooks. Give required custom fields defaults or populate them in a hook. If creation fails, sign-in fails. Trashed users are excluded from identity lookup; duplicate or incompatible email identities are rejected. Session issuance respects account lockout, collection session and cookie settings, and runs beforeLogin and afterLogin. The callback sets the session cookie and never returns provider tokens. It answers with a small page that continues to returnTo (a <meta http-equiv="refresh">) rather than a redirect: browsers mark the callback’s load cross-site because it comes from the provider, and with serverURL set the session cookie doesn’t count on a cross-site load, so a redirect’s target would not see the user until a reload. The page’s own navigation is same-origin, so returnTo sees the user on its first load. For collections with sign-in methods, FrogBot coordinates OAuth and password login, logout, refresh, and password reset through the end of each operation. Operations serialize per collection to prevent concurrent requests from restoring revoked sessions. Use FrogBot’s public API and normal auth endpoints; direct database operations bypass this coordination. Persisted sessions require transactional storage. SQLite, PostgreSQL, and MongoDB replica sets are supported; session mutations fail rather than falling back to unsafe transactionless writes. Keep login hooks short. For long SQLite transactions, use an independent KV backend so the transaction cannot block renewal of the authentication lock. The SQLite adapter enables transactions automatically when you configure sign-in methods. Explicitly disabling transactions with sign-in configured produces an initialization error.

Who can sign up

Creating a user through sign-in follows the collection’s access.create, the same rule as POST /api/users. It runs with no signed-in user, and data holds the normalized email. The default create access allows only a signed-in user, so without access.create, only people who already have an account can sign in.
The rule also governs POST /api/users, so an open rule lets anyone create an account there too. An allow() rule needs a signed-in user, so it refuses every new person; open sign-up with a plain function. Refused people get a 403 with “This app doesn’t let new people sign up. Ask an admin to add you.” and nothing is created. The first user is the exception, as with the create-first-user screen: while the collection has no users at all, counting trashed ones, the first person to sign in gets an account whatever access.create says. Sign-ins to a collection run one at a time, so two people signing in at once can’t both become the first user. On Dojo, the Dojo plugin adds “Continue with Dojo” to the user collection, and it follows these same rules.

Collection requirements

  • Each sign-in method needs factory OAuth app credentials and a recipe with an account function. Method slugs must be URL-safe and unique within the collection.
  • Keep a unique, stored, non-localized email field. Sign-in requires email identity even if you also support usernames.
  • For an OAuth-only collection, set disableLocalStrategy: { enableFields: true }. Identity and session fields remain, FrogBot authenticates the sign-in session cookie itself, and password login, forgot and reset password, unlock, and first-user registration are refused.
  • auth.strategies authenticates later requests. auth.signIn configures interactive login methods.

Share an app with Gmail connections

Gmail extends Google’s OAuth recipe with mailbox scopes. Reuse the same app credentials while keeping login and Gmail authorization separate:
Pass connections to your root config. Register both callback URIs in the shared Google app: Core auth and connections share private OAuth helpers, but their state intents and public callbacks are separate. Login never stores provider tokens or creates connections; linking never logs a user in. Users link Gmail separately in Settings → Linked accounts. For Sheets, Drive, and Calendar, use createGoogleSheets, createGoogleDrive, and createGoogleCalendar with the same oauth: google.oauth pattern. Each needs its own connections entry and product callback. The identity-only google instance does not grant product access. See Google product connection setup.