MMashDiv

Sign-in methods

How customers create accounts and sign in to the app — email and password, Google, two-factor codes — which parts the app's configuration controls and which your server's settings decide, why only the built-in proof-of-work captcha works from the app, and what the app does not offer.

12 min readUpdated 26 September 2026mobile, sign-in, registration, google, two-factor, 2fa, captcha, email-verification, password-reset

The app signs customers in to your server with the same accounts they use on your website. Most of what happens during sign-in — whether an email must be verified, whether a two-factor code is asked for, which captcha guards registration — is decided by your server's settings, and the app follows them. The only sign-in keys in app_config.json are the two for Google.

What In the app Decided by
Sign in with email and password Always offered —
Create an account Always offered Server: Email Verification Required, Captcha Provider
Verify an email address Finished on your website, from the emailed link Server: Email Verification Required
Forgot or change a password Requested in the app, finished on your website Server: Captcha Provider
Google Optional. Signs in accounts already linked to Google; never creates one App: googleServerClientId, googleAuthEnabled. Server: NEXT_PUBLIC_GOOGLE_CLIENT_ID
Two-factor codes Asked for at sign-in; set up in the app Server: the Two-Factor Authentication settings
Captcha Built-in proof-of-work only Server: Captcha Provider
Wallet (Web3) sign-in Not offered —

The server settings on this page are on Admin → System → Platform Settings, on the Security tab. A switch that has never been saved counts as on. See Settings reference.

Email and password

Creating an account

The registration screen asks for first and last name, email address, a password (typed twice), and an optional referral code. What happens next depends on Email Verification Required (verifyEmailStatus, in the Authentication group):

  • On (the default). The server answers "Registration successful, please verify your email". The app shows that message and returns to the sign-in screen. The customer is not signed in until they verify.
  • Off. The customer is signed in straight away.

Registration from the app goes through the server's captcha check; see Captcha. Your server also allows only three new accounts an hour from one IP address, and refuses the fourth with "Too many accounts have been created from this address. Please try again later." Keep that in mind when you test sign-ups from one office network; see Bot protection.

Email verification happens on your website

The verification email's Verify Email Address button links to your website. The app has no screen for typing the code, and it does not open links (it declares no app links or URL schemes), so the customer verifies in their browser and then signs in to the app.

A customer who signs in before verifying is refused with "User email not verified. Verification email sent.", and the server sends a fresh email.

The account you give App Review must already be verified, or the reviewer sees exactly that refusal.

Forgotten and changed passwords

  • Forgot Password? on the sign-in screen asks for the email address and has your server send the reset email. The link in it opens your website, where the customer chooses the new password. Then they sign in to the app with it.
  • Change Password (in the app's Security screen) does not change the password in place. It signs the customer out and sends them through the same Forgot Password? flow, because the change is confirmed by email.

Both work while your server's captcha is Proof of Work or None: under Proof of Work the app fetches a challenge for the reset and solves it before it sends the request, as it does for registration. With a hosted captcha they are refused, and the reset screen says to use the website; see Captcha.

After Change Password, the customer can sign in to the app again as soon as they have chosen the new password. (Before 5.4.0 the next sign-in answered "An error occurred. Please restart the app." until the app was restarted.)

Refusals at sign-in

These come from your server and appear on the sign-in screen as written:

Message Why
Incorrect email or password Wrong email or password
User email not verified. Verification email sent. Email Verification Required is on and the address is unverified
Too many failed login attempts, account temporarily blocked Five failed passwords on the account. It unlocks five minutes after the last failure
Too many login attempts. Please try again in a few minutes. Thirty attempts in fifteen minutes from one IP address
Your account has been banned. Please contact support. The account's status is banned
Your account is suspended. Please contact support. The account's status is suspended
Your account is inactive. Please verify your email or contact support. The account's status is inactive

The per-IP limit counts the address your server sees. If your reverse proxy is on another machine and your server is not told to trust it, every customer appears to come from the proxy's address and shares one limit. See Environment variables.

Google sign-in

What it can and cannot do

The Continue with Google button signs in an account that is already linked to Google. It never creates an account, on the sign-in screen or on the registration screen: both buttons do the same thing.

An account is linked to Google when it was created with Google on your website's registration page. An existing account is linked the first time its owner uses Continue with Google on your website's registration page with the same email address.

The app shows Why
This Google account is not linked. Please log in with your password first and link Google from your profile. No account on your server is linked to this Google account. The customer uses Continue with Google once on your website's registration page with the same email, or signs in with email and password
Google account email does not match linked user The account's email address and the Google account's address no longer match: one of them changed after the link was made
Failed to get Google ID token. Google returned no sign-in token, usually because googleServerClientId is empty
An error starting Google authentication failed: Your server refused the Google token, and the rest of the message says why. The usual cause is a token issued for a different client ID from the one your server checks; an unverified Google email address is another

An account with two-factor authentication turned on finishes Google sign-in on the same Verification Required code screen as a password sign-in. A completed Google sign-in is saved on the phone like a password sign-in, so the customer is still signed in when they close and reopen the app.

The app lets go of the Google account as soon as your server has answered, so every tap on Continue with Google shows Google's account picker. A customer refused with "This Google account is not linked" can choose another account, and on a shared phone the next person does not get the previous person's account.

Before 5.4.0 every Google sign-in from the app failed with "Unexpected error during Google sign in", with or without two-factor. If you turned Google off in the app for that reason, you can turn it back on with this release.

One limit to tell customers about:

  • Password-less accounts cannot delete themselves in the app. An account created with Google on your website has no password, and the app's Delete Account screen confirms with a password. Those customers close their account through your support team; your website's public Delete your account page (/account-deletion) tells them how.

Set it up

  1. Find your Web client ID. Google sign-in on the app uses the same Google Cloud project and the same OAuth Web client ID as your website: the value of NEXT_PUBLIC_GOOGLE_CLIENT_ID in your server's .env. If your website's Google sign-in works, you already have it.

  2. Put it in the app. In app_config.json, set googleServerClientId to that Web client ID, and googleAuthEnabled to true (or leave googleAuthEnabled out: the button then shows whenever googleServerClientId is set, and stays hidden while it is empty).

    {
      "googleServerClientId": "1234567890-abc123.apps.googleusercontent.com",
      "googleAuthEnabled": true
    }
  3. Register the Android app with Google. In the same Google Cloud project, create an OAuth client of type Android with your androidApplicationId and the SHA-1 fingerprint of the key that signs the build. Google requires it before it issues a token to an Android app. A build installed from Google Play is signed with Play's app signing key, whose SHA-1 is in Play Console; your own test builds are signed with your upload or debug key. Register each one you use.

  4. Set up iOS, as in the next section, if you build for iOS.

  5. Build and test on a real device with an account that is already linked to Google.

The installers (setup/installers/install.sh and install.bat) leave googleAuthEnabled out of the file they write, so the button follows the Google client ID you give them: shown if you gave one, hidden if you left it empty.

On Android, the Google plugin can also take the Web client ID from google-services.json when googleServerClientId is empty. The button does not look there: if you rely on google-services.json for the client ID, set "googleAuthEnabled": true yourself.

iOS needs three entries the project does not ship

The iOS project ships without the Google entries its Info.plist needs for Google sign-in. Add them before you offer Google on iOS:

  1. Create an iOS client. In the same Google Cloud project, create an OAuth client of type iOS with your iosBundleId. Note its client ID (ending .apps.googleusercontent.com) and its reversed client ID (the same value the other way round, starting com.googleusercontent.apps.).

  2. Add the entries to ios/Runner/Info.plist, inside the top-level <dict>:

    <key>GIDClientID</key>
    <string>1234567890-iosclient.apps.googleusercontent.com</string>
    <key>GIDServerClientID</key>
    <string>1234567890-webclient.apps.googleusercontent.com</string>
    <key>CFBundleURLTypes</key>
    <array>
      <dict>
        <key>CFBundleTypeRole</key>
        <string>Editor</string>
        <key>CFBundleURLSchemes</key>
        <array>
          <string>com.googleusercontent.apps.1234567890-iosclient</string>
        </array>
      </dict>
    </array>

    GIDClientID is the iOS client ID, the URL scheme is its reversed client ID, and GIDServerClientID is the same Web client ID as googleServerClientId.

  3. Build and test on an iPhone.

Why GIDServerClientID is needed as well as googleServerClientId: on iOS, the Google sign-in plugin passes the app's googleServerClientId on to Google only when the project also contains a GoogleService-Info.plist that carries a CLIENT_ID. Without one, Google's iOS library takes its settings from Info.plist, and a token issued without your Web client ID is refused by your server.

These entries follow the Google sign-in plugin's own iOS instructions and the plugin's code. At the time of writing, Google sign-in had not been run on an iPhone against this app. Test it on a device before you submit.

Info.plist is part of the project, so a new release's ios/ folder does not carry these entries. Add them again after every update that replaces it.

The app has no Sign in with Apple. Apple's App Review Guidelines have a rule on login services (guideline 4.8) that applies to apps offering a third-party sign-in such as Google. Read it before you ship Google sign-in in your iOS build.

What your server needs

  • NEXT_PUBLIC_GOOGLE_CLIENT_ID in your server's .env, set to the Web client ID. Your server checks every Google token from the app against it. See Environment variables.
  • Google OAuth Login (googleAuthStatus, Security → Authentication) shows or hides the Google button on your website only. The app ignores it: turning it off does not remove the button from the app, and turning it on does not add one. The app's button follows googleAuthEnabled, or, when that key is absent, whether googleServerClientId is set.
  • Keep it on while you offer Google in the app. Accounts are linked to Google on your website, so with the website's button off, no new account can be linked and the app's button only works for accounts linked before.

Two-factor authentication

Two-factor authentication is decided entirely by your server. The Two-Factor Authentication group on the Security tab has four switches:

Setting Key What it does in the app
Two-Factor Authentication twoFactorStatus The master switch. Off: the app's sign-in asks for no code, even from customers who set two-factor up
SMS 2FA twoFactorSmsStatus Codes by SMS. Needs an SMS provider configured on your server
Email 2FA twoFactorEmailStatus Codes by email
Authenticator App 2FA twoFactorAppStatus Codes from an authenticator app

At sign-in, after a correct password (or Google), a customer with two-factor turned on gets a Verification Required screen and types the six-digit code from their method into six boxes; the sixth digit submits it. SMS and email codes can be sent again from that screen.

The same screen also takes one of the customer's recovery codes, for a customer who has lost their phone or authenticator. The link Can't get a code? Use a recovery code, under Verify Code, swaps the six boxes for a single Recovery code field that shows XXXX-XXXX-XXXX as its hint. The customer types the code with or without its dashes; the app drops any spaces before sending it, and your server ignores dashes and letter case. Each recovery code works once. Use a verification code instead switches back.

Setting it up happens in the app under Profile → Security → Two-Factor Authentication. The app always offers all three methods — Authenticator App, SMS Messages and Email — whatever your switches say. A method your server has off fails when the customer picks it, with "SMS 2FA is not enabled", "Email 2FA is not enabled" or "App 2FA is not enabled". SMS also needs a phone number: "Phone number is required for SMS". After setup, the app shows the account's recovery codes once.

If you switch SMS 2FA or Email 2FA off while customers are signed up to that method, their next sign-in in the app still reaches the Verification Required screen, but no code is sent. The only way through is one of their recovery codes, through Can't get a code? Use a recovery code. SMS customers are stranded the same way when no SMS provider is configured on your server. Move those customers to another method first, or leave the method on.

Two-factor codes for withdrawals and transfers follow the Withdrawal Security and Transfer Security groups on the same tab. See Settings reference.

Captcha: the app supports the built-in proof-of-work

Captcha Provider (captchaProvider, in the Protection group) chooses the captcha your server requires for registration, password reset and sign-in on your website. For the app:

Captcha Provider Registration from the app Forgot / Change Password from the app
Proof of Work (built-in, no keys) — the default Works Works
None — no captcha at all Works Works
Cloudflare Turnstile, Google reCAPTCHA v3 or hCaptcha Refused Refused

Signing in from the app never uses a captcha, so sign-in works with every provider.

With proof-of-work, the app asks your server for a fresh challenge for that action (registration or password reset) and solves it on the phone before it sends the form. The customer sees nothing but a short pause on the button. PoW Difficulty sets how long that pause is.

The hosted providers (Turnstile, reCAPTCHA, hCaptcha) need their own widget to produce a token, and the app includes none of them. Their check therefore fails: the server refuses the request ("Security verification failed. Please try again."), and the app tells the customer to use the website instead:

This server's security check can only be completed on the website. Please create your account on the website, then sign in here.

For a password reset, the second sentence reads "Please reset your password on the website, then sign in here with your new password." On the reset screen the message stays on the page, above Send Reset Link, until the customer tries again; on the registration screen it appears as a message at the bottom of the screen.

If the hosted provider's secret key is missing, your server cannot run the check at all. It then refuses registration with "Registration is temporarily unavailable. Please try again shortly.", and lets a password reset through without a check.

If you use a hosted provider, your customers sign up and reset passwords on your website, and then sign in to the app. If most of your customers join from the app, use Proof of Work. See Bot protection for what each provider protects on the website.

What the app does not offer

  • Wallet (Web3) sign-in. The app has no wallet sign-in, whatever your website offers. A customer who uses a wallet on your website signs in to the app with their email address and password instead.
  • Creating an account with Google. See What it can and cannot do.
  • Verifying an email or resetting a password inside the app. The emailed links open your website.
  • Changing a password in place. It goes through the emailed reset.
  • Sign in with Apple, or any other sign-in provider.
  • A way around your server's settings. Nothing in app_config.json turns off email verification, two-factor authentication or the captcha. The app has no switch for them; your server's settings apply to the app and the website alike.