SMS Bridge
SMS delivery for OTP codes, MFA verification, and phone number verification.
The SMS bridge provides SMS delivery for all Authsome phone-based flows: SMS-based MFA one-time passwords, phone number verification during sign-up, and phone-based magic link delivery. You provide the SMS provider implementation; Authsome provides the message content.
If you need multi-channel delivery (email + SMS + push) or template management, use the Herald bridge instead — Herald supersedes both the Mailer and SMS bridges when configured.
Interface
The bridge.SMSSender interface is defined in github.com/xraph/authsome/bridge:
type SMSSender interface {
SendSMS(ctx context.Context, msg *SMSMessage) error
}
type SMSMessage struct {
To string `json:"to"` // E.164 format, e.g. "+14155551234"
Body string `json:"body"` // Plain text message body
}Setup with a Twilio adapter
import (
"github.com/xraph/authsome"
"github.com/xraph/authsome/bridge/smsadapter"
)
eng, err := authsome.New(
authsome.WithStore(pgStore),
authsome.WithPlugin(mfa.New(mfa.WithSMSOTP())),
authsome.WithPlugin(phone.New()),
authsome.WithSMSSender(smsadapter.NewTwilio(
os.Getenv("TWILIO_ACCOUNT_SID"),
os.Getenv("TWILIO_AUTH_TOKEN"),
os.Getenv("TWILIO_FROM_NUMBER"), // E.164, e.g. "+12015551234"
)),
)Setup with AWS SNS
import "github.com/xraph/authsome/bridge/smsadapter"
eng, err := authsome.New(
authsome.WithStore(pgStore),
authsome.WithSMSSender(smsadapter.NewSNS(awsSession,
smsadapter.WithSNSSenderID("MyApp"),
smsadapter.WithSNSMessageType("Transactional"),
)),
)Custom implementation
Implement bridge.SMSSender directly for any SMS provider:
type VonageSMSSender struct {
client vonage.SMSClient
from string
}
func (s *VonageSMSSender) SendSMS(ctx context.Context, msg *bridge.SMSMessage) error {
_, _, err := s.client.Send(s.from, msg.To, msg.Body, nil)
return err
}
eng, err := authsome.New(
authsome.WithStore(pgStore),
authsome.WithSMSSender(&VonageSMSSender{
client: vonage.NewSMSClient(vonage.CreateAuthClient(
os.Getenv("VONAGE_API_KEY"),
os.Getenv("VONAGE_API_SECRET"),
)),
from: os.Getenv("VONAGE_FROM"),
}),
)SMS messages sent by Authsome
| Trigger | Message body |
|---|---|
| MFA OTP (SMS) | "Your verification code is: 123456. Valid for 5 minutes." |
| Phone verification | "Your phone verification code is: 654321. Valid for 10 minutes." |
| Magic link (phone) | "Sign in to My App: https://myapp.com/auth/magic?token=..." |
The message body is generated by Authsome's built-in templates. For fully customised SMS content, use the Herald bridge.
Phone number format
All phone numbers passed in SMSMessage.To use E.164 format: + followed by the country code and subscriber number, with no spaces or hyphens. Authsome normalises phone numbers to E.164 when users provide them during sign-up or phone verification.
Examples:
- US:
+14155551234 - UK:
+441234567890 - Germany:
+4915123456789
Standalone development stub
During development, use the built-in NoopSMSSender stub that returns ErrSMSNotAvailable for all calls:
import "github.com/xraph/authsome/bridge"
eng, err := authsome.New(
authsome.WithStore(memory.New()),
authsome.WithSMSSender(bridge.NewNoopSMSSender()),
)For development testing of MFA SMS flows without a real carrier, you can use an inline function adapter that captures OTP codes:
var lastOTP string
eng, err := authsome.New(
authsome.WithStore(memory.New()),
authsome.WithSMSSender(bridge.SMSSender(bridge.SMSMessage{
// Not a real interface, use a custom test struct
})),
)
// Or implement a test SMS sender directly:
type TestSMSSender struct {
Messages []*bridge.SMSMessage
mu sync.Mutex
}
func (s *TestSMSSender) SendSMS(_ context.Context, msg *bridge.SMSMessage) error {
s.mu.Lock()
defer s.mu.Unlock()
s.Messages = append(s.Messages, msg)
return nil
}When no SMS bridge is configured, Authsome's phone plugin and SMS-based MFA return errors when SMS delivery is attempted. Always configure an SMS sender in any environment where phone-based auth methods are enabled.