sdk

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 21, 2026 License: MIT Imports: 12 Imported by: 0

README

LessOTP Go SDK

Client for the LessOTP Inbound Phone Authentication API (Go 1.21+), supporting WhatsApp by default and Telegram as an additive channel.

Install

go get github.com/lessotp/sdk/go

Usage

package main

import (
    "context"
    "fmt"
    "log"
    "os"

    sdk "github.com/lessotp/sdk/go"
)

func main() {
    // production (default)
    client, err := sdk.NewClient(sdk.Options{
        APIKey:  os.Getenv("LESSOTP_API_KEY"),
        BaseURL: "https://api.lessotp.com",
    })
    if err != nil {
        log.Fatal(err)
    }

    // staging
    staging, err := sdk.NewClient(sdk.Options{
        APIKey:      os.Getenv("LESSOTP_STAGING_API_KEY"),
        Environment: sdk.EnvironmentStaging,
        BaseURL:     "https://api.lessotp.com",
    })
    if err != nil {
        log.Fatal(err)
    }

    phone := "6281234567890"

    // WhatsApp strict (backward-compatible default)
    wa, err := client.AuthRequest(context.Background(), &phone)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(wa.WaLink)

    // WhatsApp frictionless
    waFrictionless, err := client.AuthRequest(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(waFrictionless.WaLink)

    // Telegram strict
    tg, err := client.RequestTelegramAuth(context.Background(), &phone)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(tg.TelegramLink, tg.TelegramText)

    // Telegram frictionless
    tgFrictionless, err := client.RequestTelegramAuth(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(tgFrictionless.TelegramLink)

    // Generic multi-channel call
    _, err = client.RequestAuth(context.Background(), sdk.AuthRequestParams{
        Channel:     sdk.ChannelTelegram,
        PhoneNumber: &phone,
    })
    if err != nil {
        log.Fatal(err)
    }

    // per-call endpoint override
    _, err = client.RequestTelegramAuth(context.Background(), nil, sdk.AuthRequestOptions{
        Environment: sdk.EnvironmentStaging,
    })
    if err != nil {
        log.Fatal(err)
    }

    _ = staging
}

Telegram requests return TelegramLink and TelegramText. The end user opens the bot link, sends /start {code}, then taps Telegram's official Share phone number button. LessOTP verifies Telegram ownership with Telegram's contact payload; manually typed phone numbers are not accepted as Telegram identity.

Webhook verification

func handler(w http.ResponseWriter, r *http.Request, secret string) {
    body, _ := io.ReadAll(r.Body)
    if !sdk.VerifyWebhookSignature(body, r.Header.Get("X-Signature"), secret) {
        http.Error(w, "bad signature", http.StatusForbidden)
        return
    }
    event, err := sdk.ParseVerificationSuccess(body)
    if err != nil {
        http.Error(w, "bad payload", http.StatusBadRequest)
        return
    }
    log.Printf("verified %s channel=%s phone=%s", event.RequestID, event.Channel, event.PhoneNumber)
    if event.Channel == sdk.ChannelTelegram {
        log.Printf("telegram user id=%s username=%s", event.TelegramUserID, event.TelegramUsername)
    }
}

API

NewClient(Options) (*Client, error)

Constructor parameter order follows the shared LessOTP SDK standard: apiKey → environment → baseUrl → timeout → transport.

Field Default Description
APIKey required App API key.
Environment EnvironmentProduction EnvironmentProduction or EnvironmentStaging.
BaseURL https://api.lessotp.com API host.
Timeout 10s HTTP timeout.
HTTPClient http.Client{Timeout: …} Custom client.
(*Client).AuthRequest(ctx, *phoneNumber, opts...) (AuthRequestResult, error)

Backward-compatible WhatsApp request. Calls the endpoint selected by Options.Environment. AuthRequestOptions{Environment: ...} overrides per call.

(*Client).RequestWhatsAppAuth(ctx, *phoneNumber, opts...) (AuthRequestResult, error)

Explicit WhatsApp helper. Passing nil uses frictionless mode.

(*Client).RequestTelegramAuth(ctx, *phoneNumber, opts...) (AuthRequestResult, error)

Telegram helper. Passing a phone number uses strict mode; passing nil uses frictionless mode.

(*Client).RequestAuth(ctx, AuthRequestParams, opts...) (AuthRequestResult, error)

Generic multi-channel request. AuthRequestParams.Channel accepts ChannelWhatsApp or ChannelTelegram and defaults to WhatsApp when empty.

VerifyWebhookSignature(rawBody, signatureHeader, secret) bool

Constant-time HMAC-SHA256 verification. Accepts sha256= prefix.

ParseVerificationSuccess(rawBody) (VerificationSuccess, error)

Parses an already-verified payload. Payloads without channel are treated as WhatsApp for backward compatibility. Telegram payloads populate TelegramUserID and TelegramUsername when present.

Tests

go test ./...

Documentation

Overview

Package sdk provides a lightweight LessOTP API client and webhook verification helpers.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func VerifyWebhookSignature

func VerifyWebhookSignature(rawBody []byte, signatureHeader string, secret string) bool

VerifyWebhookSignature returns true when signatureHeader is a valid HMAC-SHA256 of rawBody using secret. Accepts both raw hex and `sha256=` prefixed values. Always returns a boolean; never panics on malformed input.

Types

type AuthRequestOptions

type AuthRequestOptions struct {
	Environment Environment
}

AuthRequestOptions are optional per-request overrides.

type AuthRequestParams added in v0.2.0

type AuthRequestParams struct {
	// Channel defaults to ChannelWhatsApp when empty.
	Channel VerificationChannel
	// PhoneNumber enables strict mode. Nil means frictionless mode.
	PhoneNumber *string
}

AuthRequestParams configure a multi-channel auth request.

type AuthRequestResult

type AuthRequestResult struct {
	RequestID    string              `json:"request_id"`
	UniqueCode   string              `json:"unique_code"`
	Channel      VerificationChannel `json:"channel"`
	WaLink       string              `json:"wa_link,omitempty"`
	TelegramLink string              `json:"telegram_link,omitempty"`
	TelegramText string              `json:"telegram_text,omitempty"`
	ExpiresIn    int                 `json:"expires_in"`
	Mode         VerificationMode    `json:"mode"`
}

AuthRequestResult is the normalized response of POST /api/v1/auth/request.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is a stateless HTTP client for the LessOTP API. Safe for concurrent use.

func NewClient

func NewClient(opts Options) (*Client, error)

NewClient constructs a Client from the provided Options.

func (*Client) AuthRequest

func (c *Client) AuthRequest(ctx context.Context, phoneNumber *string, opts ...AuthRequestOptions) (AuthRequestResult, error)

AuthRequest creates a WhatsApp verification request.

If phoneNumber is nil, the request is frictionless. Otherwise the phoneNumber is sent as strict-mode `phone_number`. The endpoint is selected from AuthRequestOptions.Environment when provided, otherwise the Client's environment. This method is kept for backward compatibility; use RequestAuth or RequestTelegramAuth for explicit multi-channel calls.

func (*Client) RequestAuth added in v0.2.0

func (c *Client) RequestAuth(ctx context.Context, params AuthRequestParams, opts ...AuthRequestOptions) (AuthRequestResult, error)

RequestAuth creates a multi-channel verification request.

Channel defaults to WhatsApp for backward compatibility. Endpoint selection follows the client environment unless overridden per call.

func (*Client) RequestTelegramAuth added in v0.2.0

func (c *Client) RequestTelegramAuth(ctx context.Context, phoneNumber *string, opts ...AuthRequestOptions) (AuthRequestResult, error)

RequestTelegramAuth creates a Telegram verification request.

Strict mode: pass phoneNumber. Frictionless mode: pass nil. Telegram users always verify by tapping the official Share phone number button; LessOTP does not accept manually typed phone numbers as Telegram identity.

func (*Client) RequestWhatsAppAuth added in v0.2.0

func (c *Client) RequestWhatsAppAuth(ctx context.Context, phoneNumber *string, opts ...AuthRequestOptions) (AuthRequestResult, error)

RequestWhatsAppAuth creates a WhatsApp verification request.

type Environment

type Environment string

Environment selects the endpoint family. Production is the default.

const (
	EnvironmentProduction Environment = "production"
	EnvironmentStaging    Environment = "staging"
)

type Options

type Options struct {
	APIKey      string
	Environment Environment   // default: production
	BaseURL     string        // default: https://api.lessotp.com
	Timeout     time.Duration // default: 10s
	HTTPClient  *http.Client
}

Options configure a Client. All fields are optional except APIKey.

type VerificationChannel added in v0.2.0

type VerificationChannel string

VerificationChannel selects the inbound phone authentication channel. WhatsApp is the default for backward compatibility.

const (
	ChannelWhatsApp VerificationChannel = "whatsapp"
	ChannelTelegram VerificationChannel = "telegram"
)

type VerificationMode

type VerificationMode string

VerificationMode is the `mode` value returned by LessOTP's auth request API.

const (
	ModeStrict       VerificationMode = "strict"
	ModeFrictionless VerificationMode = "frictionless"
)

type VerificationSuccess

type VerificationSuccess struct {
	Event            string              `json:"event"`
	Channel          VerificationChannel `json:"channel,omitempty"`
	RequestID        string              `json:"request_id"`
	PhoneNumber      string              `json:"phone_number"`
	TelegramUserID   string              `json:"telegram_user_id,omitempty"`
	TelegramUsername string              `json:"telegram_username,omitempty"`
	Timestamp        string              `json:"timestamp,omitempty"`
}

VerificationSuccess represents a `verification.success` webhook payload.

func ParseVerificationSuccess

func ParseVerificationSuccess(rawBody []byte) (VerificationSuccess, error)

ParseVerificationSuccess parses a `verification.success` payload. The caller must verify the signature first using VerifyWebhookSignature.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL