New in v2.7.0

Phone + OTP

Sign users in with their phone number. Koolbase sends a 6-digit verification code via SMS, the user enters it, and a session is issued automatically. Ideal for emerging markets and apps where email isn't the primary identifier.

How it works

  1. Configure an SMS provider for your project (Twilio, Africa's Talking, or Hubtel).
  2. The user enters their phone number and you call sendOtp. Koolbase generates a 6-digit code, stores it SHA-256 hashed in Redis with a 5-minute TTL, and sends it via your provider.
  3. The user enters the code and you call verifyOtp. Koolbase verifies it, creates the user account on first sign-in, and returns a full session.

Supported SMS providers

Twilio

Global

Africa's Talking

Africa-wide

Hubtel

Ghana

For Ghana traffic specifically, Hubtel typically delivers better and at lower cost than Twilio. Africa's Talking is a strong middle ground for multi-country African deployments. Twilio is the global default and easiest to test with.

Configure your SMS provider

Each project picks one SMS provider. Provider credentials are encrypted and stored per project.

Dashboard UI coming soon

The dashboard form for configuring SMS providers is in progress. For now, configure your provider via the API directly using your dashboard JWT.

Twilio

curlShell
curl -X PUT https://api.koolbase.com/v1/projects/{project_id}/sms-config \
  -H "Authorization: Bearer YOUR_DASHBOARD_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "provider": "twilio",
    "credentials": {
      "account_sid": "ACxxxxxxxxxxxxxxxx",
      "auth_token": "your_auth_token",
      "from_number": "+15551234567"
    },
    "sender_id": "YourApp"
  }'

Africa's Talking

curlShell
curl -X PUT https://api.koolbase.com/v1/projects/{project_id}/sms-config \
  -H "Authorization: Bearer YOUR_DASHBOARD_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "provider": "africas_talking",
    "credentials": {
      "api_key": "your_api_key",
      "username": "your_username"
    },
    "sender_id": "YourApp"
  }'

Hubtel

curlShell
curl -X PUT https://api.koolbase.com/v1/projects/{project_id}/sms-config \
  -H "Authorization: Bearer YOUR_DASHBOARD_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "provider": "hubtel",
    "credentials": {
      "client_id": "your_client_id",
      "client_secret": "your_client_secret"
    },
    "sender_id": "YourApp"
  }'

Send OTP

Send a 6-digit code to a phone number in E.164 format. The returned expiresAt timestamp can power a resend countdown timer.

Flutter

lib/auth.dartDart
import 'package:koolbase_flutter/koolbase_flutter.dart';

final result = await Koolbase.auth.sendOtp(
  phoneNumber: '+233244000000',
);

print('Code expires at: ${result.expiresAt}');

React Native

App.tsxTypeScript
import { Koolbase } from '@techfinityedge/koolbase-react-native';

const result = await Koolbase.auth.sendOtp({
  phoneNumber: '+233244000000',
});

console.log('Code expires at:', result.expiresAt);

Verify OTP and sign in

Once the user enters the code, verify it. If no user exists with this phone number, Koolbase creates one. The isNewUser flag lets you route first-time users to onboarding.

Flutter

lib/auth.dartDart
final result = await Koolbase.auth.verifyOtp(
  phoneNumber: '+233244000000',
  code: '123456',
);

if (result.isNewUser) {
  // First time — route to onboarding
} else {
  // Returning user — route to home
}

print('Signed in as: ${result.session.user.id}');

React Native

App.tsxTypeScript
const result = await Koolbase.auth.verifyOtp({
  phoneNumber: '+233244000000',
  code: '123456',
});

if (result.isNewUser) {
  navigation.navigate('Onboarding');
} else {
  navigation.navigate('Home');
}

console.log('Signed in as:', result.session.user.id);

Sessions are issued automatically

On successful verify, the session is stored in the SDK and used for subsequent authenticated requests. You don't need to manage tokens manually.

Link a phone to an existing account

For users who originally signed up with email or OAuth and want to add phone-based sign-in or 2FA, use linkPhone. The user must already be authenticated and must have requested an OTP for the phone number first.

Flutter

lib/auth.dartDart
// 1. Send OTP to the phone the user wants to link
await Koolbase.auth.sendOtp(phoneNumber: '+233244000000');

// 2. After user enters code, link it to their account
await Koolbase.auth.linkPhone(
  phoneNumber: '+233244000000',
  code: '123456',
);

// User can now also sign in via phone+OTP

React Native

App.tsxTypeScript
await Koolbase.auth.sendOtp({ phoneNumber: '+233244000000' });

await Koolbase.auth.linkPhone({
  phoneNumber: '+233244000000',
  code: '123456',
});

Error handling

Each error condition has a typed exception so you can build clear UX for each case.

Flutter

lib/auth.dartDart
try {
  final result = await Koolbase.auth.verifyOtp(
    phoneNumber: phone,
    code: code,
  );
} on OtpExpiredException {
  // Show "Code expired — request a new one"
} on OtpMaxAttemptsException {
  // Lock the form, force a fresh send
} on OtpInvalidException {
  // "That code is incorrect"
} on OtpRateLimitException {
  // "Please wait before requesting another code"
} on InvalidPhoneNumberException {
  // Format error — fix and retry
}

React Native

App.tsxTypeScript
import {
  Koolbase,
  OtpExpiredError,
  OtpInvalidError,
  OtpMaxAttemptsError,
  OtpRateLimitError,
} from '@techfinityedge/koolbase-react-native';

try {
  const result = await Koolbase.auth.verifyOtp({
    phoneNumber: phone,
    code,
  });
} catch (e) {
  if (e instanceof OtpExpiredError) {
    // Code expired
  } else if (e instanceof OtpInvalidError) {
    // Wrong code
  } else if (e instanceof OtpMaxAttemptsError) {
    // Too many tries
  } else if (e instanceof OtpRateLimitError) {
    // Too many requests
  }
}

Phone number format

All phone numbers must be in E.164 format: a +, country code, and subscriber number with no spaces, dashes, or parentheses. Validation runs both client-side in the SDK and server-side in the API.

Valid
  +233244000000     Ghana
  +14155551234      United States
  +442079460000     United Kingdom

Invalid (will fail SDK validation)
  0244000000        — missing country code
  +233 244 000 000  — spaces not allowed
  +233-244-000000   — dashes not allowed

Rate limits

To prevent SMS pumping abuse and keep your provider costs down, Koolbase enforces two rate limits:

  • Per phone number: 3 OTP requests per 10 minutes.
  • Per IP address: 10 OTP requests per hour.

Hitting either limit returns 429 Too Many Requests, surfaced as OtpRateLimitException in Flutter and OtpRateLimitError in React Native.

OTP details

  • Length: 6 digits, randomly generated.
  • Expiry: 5 minutes from send time.
  • Max attempts: 3 incorrect attempts invalidate the code.
  • Storage: SHA-256 hashed in Redis — never stored in plaintext.
  • Single use: codes are deleted on successful verify.

API reference

MethodDescription
Koolbase.auth.sendOtp(phoneNumber)Send a 6-digit code via SMS
Koolbase.auth.verifyOtp(phoneNumber, code)Verify the code and sign in or sign up
Koolbase.auth.linkPhone(phoneNumber, code)Link a phone number to the current authenticated user