Authsome

Phone Plugin

Phone number verification and OTP-based authentication with automatic user provisioning.

The phone plugin provides phone number authentication as a primary auth method. Users enter their phone number, receive an OTP via SMS, and verifying the code authenticates them. The plugin supports automatic user creation for new phone numbers.

Setup

import (
    "github.com/xraph/authsome"
    "github.com/xraph/authsome/plugins/phone"
)

eng, err := authsome.NewEngine(
    authsome.WithStore(store),
    authsome.WithSMSSender(smsBridge),
    authsome.WithPlugin(phone.New(phone.Config{
        CodeTTL:    5 * time.Minute,
        AutoCreate: boolPtr(true),
    })),
)

func boolPtr(v bool) *bool { return &v }

Configuration

OptionTypeDefaultDescription
SMSSenderbridge.SMSSenderengine SMS bridgeOverride the engine-level SMS sender
CodeTTLtime.Duration5mLifetime of OTP codes
AutoCreate*booltrueCreate new users for unregistered phone numbers

Implemented interfaces

InterfacePurpose
PluginBase plugin identity ("phone")
OnInitCaptures store, SMS sender, ceremony store, logger, and session config resolver
RouteProviderRegisters /v1/auth/phone/start and /verify endpoints
AuthMethodContributorReports "phone" as a linked auth method if the user has a verified phone

Authentication flow

Send OTP: The user submits their phone number in E.164 format.

POST /v1/auth/phone/start

{
  "phone": "+14155551234",
  "app_id": "myapp"
}

The plugin validates the phone number format (E.164: + followed by 7-15 digits), generates a 6-digit OTP using the MFA SMS infrastructure, sends it via the SMS bridge, and stores the challenge in the ceremony store.

Response:

{
  "status": "otp_sent",
  "expires_in": 300
}

Verify OTP: The user enters the received code.

POST /v1/auth/phone/verify

{
  "phone": "+14155551234",
  "code": "123456",
  "app_id": "myapp"
}

The plugin validates the code against the stored challenge, resolves or creates the user, marks the phone number as verified, and creates a session.

Response:

{
  "user": {
    "id": "ausr_01j9...",
    "phone": "+14155551234",
    "phone_verified": true
  },
  "session_token": "a3f8c9d4...",
  "refresh_token": "d72b1ef8...",
  "expires_at": "2024-11-01T11:00:00Z",
  "new_user": true
}

Phone number validation

The plugin validates phone numbers against the E.164 format using a regex pattern:

^\+[1-9]\d{6,14}$

Examples of valid phone numbers:

  • +14155551234 (US)
  • +442071234567 (UK)
  • +81312345678 (Japan)

Invalid formats are rejected with a 400 Bad Request error.

Auto-creation behavior

When AutoCreate is true (the default), the plugin creates new users automatically when an unregistered phone number is verified. The new user has:

  • A new user ID
  • The phone number set and marked as verified
  • No email, name, or password

When AutoCreate is false, unregistered phone numbers receive a 401 Unauthorized error. This is useful when phone auth should only work for existing users who have already linked their phone number.

// Disable auto-creation:
phone.New(phone.Config{
    AutoCreate: boolPtr(false),
})

Integration with SMS bridge

The phone plugin uses the SMS bridge interface:

type SMSSender interface {
    SendSMS(ctx context.Context, to, message string) error
}

The OTP code generation and validation reuses the MFA plugin's SMS infrastructure (mfa.SendSMSChallenge and mfa.ValidateSMSCode).

Rate limiting

OTP sends should be rate-limited to prevent abuse. Configure rate limiting at the engine level:

authsome.WithRateLimiter(rateLimiter)

The engine applies rate limits to all authentication endpoints, including phone OTP sends.

Auth method reporting

The phone plugin implements AuthMethodContributor, reporting phone as a linked method when the user has a verified phone number:

{
  "type": "phone",
  "provider": "phone",
  "label": "Phone (+14155551234)",
  "linked_at": "2024-11-01T10:00:00Z"
}

API routes

MethodPathDescription
POST/v1/auth/phone/startSend OTP to phone number
POST/v1/auth/phone/verifyVerify OTP and authenticate

On this page