Email Code

Sign in with a six-digit code sent to the inbox — no password. The person enters their email, receives a code, types it into your app, and they're in.

Two calls

Flutter
dart
// Send a code to the address
await Koolbase.auth.requestEmailCode('[email protected]');

// Sign in with it
final user = await Koolbase.auth.signInWithEmailCode(
  email: '[email protected]',
  code: '123456',
);
JavaScript / React Native
typescript
await Koolbase.auth.requestEmailCode({ email: '[email protected]' });

const session = await Koolbase.auth.signInWithEmailCode({
  email: '[email protected]',
  code: '123456',
});

The session is stored exactly as with email-and-password sign-in, and the person's email is marked verified — the code reached their inbox, which proves they own it. Requires koolbase_flutter 12.7.0 or @koolbase/js / @koolbase/react-native 12.1.0.

Who gets a code

  • An existing account — the code signs them in.
  • A new address, while sign-ups are open — signing in creates the account. This is checked at the moment of sign-in, so a code sent while sign-ups were open can't create an account after they close.
  • A new address, while sign-ups are closed — no email is sent.
  • A disabled account — no email is sent.

requestEmailCode answers the same way in every one of these cases, so it can't be used to find out which addresses have accounts.

The rules for a code

  • It expires after 10 minutes.
  • It works once.
  • It allows three attempts; after that, request a new one.
  • Requesting another code replaces the previous one — only the newest works.
  • One address can request 3 codes per 10 minutes and 10 per day, with further limits per network and per project.

Why the daily limit matters

A six-digit code has a million possibilities. Three attempts per code and a few codes an hour would still let a determined attacker make over a thousand guesses a day at one address. The daily limit brings that down to about thirty, which makes guessing impractical.

Switching it off

It's on for every project by default. For password-only sign-in, open your project's auth settings and switch off Sign in with an emailed code. Requests then fail with 403 email_code_disabled, and codes sent before the switch was turned off stop working.

Being on by default doesn't widen access: anyone who controls an inbox can already take the account through a password reset. A code gives them nothing a reset didn't.

Errors

  • otp_invalid — the code is wrong; the person can try again
  • otp_max_attempts — three wrong attempts; request a new code
  • otp_expired — expired or already used; request a new code
  • rate_limit — too many codes requested; wait and try again
  • email_code_disabled — the project has switched this off
  • signups_disabled — a new address, and the project isn't accepting sign-ups
  • account_disabled — the account has been disabled

Each arrives as its own exception or error class in the SDKs — OtpInvalidException, EmailCodeDisabledException and so on — so your app can respond to each one.

A code, not a link

This is a code the person types, which works the same in any app, web or mobile, with no setup. A clickable sign-in link needs your app to handle deep links and redirects, and is a separate feature.