Go SDK

github.com/midnight-auth/sdk-go

Installation

go get github.com/midnight-auth/sdk-go

Quick Start

package main

import (
    "context"
    "fmt"
    "log"

    ma "github.com/midnight-auth/sdk-go"
)

func main() {
    client, err := ma.NewClient(ma.Config{
        BaseURL: "https://auth.yourapp.com/api/v1",
        APIKey:  "ma_your_api_key_here", // from Console → Apps
    })
    if err != nil {
        log.Fatal(err)
    }

    // Check API health
    health, err := client.Health(context.Background())
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(health.Status) // "ok"
}

Configuration

ParamTypeRequiredDescription
BaseURLstringYesMidnight Auth API base URL
APIKeystringYesPartner app API key (ma_...)
Timeouttime.DurationNoHTTP request timeout (default: 30s)

Login Flow

Your app initiates a login session, shows a QR code, and polls until the user approves in their wallet.

client.Login.Initiate(ctx, requirements, redirectURL)

Start a new login session. Returns QR code and deep link for the wallet.

ctx := context.Background()

session, err := client.Login.Initiate(ctx, []string{"email", "phone"}, "")
if err != nil {
    log.Fatal(err)
}

// session.SessionID   — unique session ID
// session.QRCodeURL   — data:image/png base64 QR code
// session.DeepLink    — midnight-auth://login?session=...
// session.ExpiresAt   — ISO timestamp (5 min TTL)
// session.AppName     — your registered app name
ParamTypeRequiredDescription
requirements[]stringYesCredential types: "email", "phone", "social", "humanity", "age"
redirectURLstringNoURL to redirect after login (pass "" to omit)

client.Login.WaitForResult(ctx, sessionID, opts)

Polls session status until verified, expired, or denied. Recommended approach.

result, err := client.Login.WaitForResult(ctx, session.SessionID,
    &ma.WaitForResultOptions{
        Timeout:  120 * time.Second,
        Interval: 2 * time.Second,
        OnStatusChange: func(status string) {
            fmt.Println("Status:", status) // "pending" → "verified"
        },
    },
)
if err != nil {
    log.Fatal(err)
}

if result.Verified {
    fmt.Println(result.UserID)      // "usr_7x8m2k..."
    fmt.Println(result.EmailDomain) // "gmail.com"
}

client.Login.GetStatus(ctx, sessionID)

Manual status check (use if you prefer custom polling).

status, err := client.Login.GetStatus(ctx, session.SessionID)
// status.Status: "pending" | "verified" | "expired" | "denied"

client.Login.GetResult(ctx, sessionID)

Fetch verified result data. Only returns data when status is "verified".

result, err := client.Login.GetResult(ctx, session.SessionID)

Login Result Struct

The result struct only contains booleans and derived metadata — never raw PII. Fields are populated only if the matching credential was required and verified.

type LoginResultResponse struct {
    Verified   bool   // true if login succeeded
    UserID     string // app-specific pseudonymous ID ("usr_7a8b3c...")
    VerifiedAt string // ISO timestamp

    // Email credential
    EmailVerified bool
    EmailDomain   string // domain only, not the address
    DomainType    string // "consumer" | "business" | "edu"

    // Phone credential
    PhoneVerified bool
    PhoneCountry  string // country code only
    CarrierType   string // "mobile" | "voip" | "landline"

    // Social credential
    HasSocial        bool
    SocialPlatform   string
    AccountAgeMonths int
    FollowerRange    string // "1k-10k"

    // Humanity credential
    IsHuman       bool
    HumanityScore float64

    // Age credential
    Over18 bool
    Over21 bool
    Over25 bool
}

Onboarding Flow

Issue verifiable credentials to users' wallets. Each step issues an ACDC credential. All methods accept a context.Context for cancellation.

ctx := context.Background()

// Step 1: Connect wallet
session, _ := client.Onboard.ConnectWallet(ctx, "D_user_keri_aid_here")

// Step 2: Email verification
_, _ = client.Onboard.SendEmailCode(ctx, session.SessionID, "user@example.com")
_, _ = client.Onboard.VerifyEmailCode(ctx, session.SessionID, "123456")

// Step 3: Phone verification
_, _ = client.Onboard.SendPhoneCode(ctx, session.SessionID, "+1234567890")
_, _ = client.Onboard.VerifyPhoneCode(ctx, session.SessionID, "654321")

// Step 4: Social auth
social, _ := client.Onboard.StartSocialAuth(ctx, "twitter", session.SessionID)
// Redirect user to social.AuthorizationURL

// Step 5: Humanity check
_, _ = client.Onboard.VerifyHumanity(ctx, session.SessionID, "hcaptcha_token")

// Check progress
status, _ := client.Onboard.GetSessionStatus(ctx, session.SessionID)
fmt.Println(status.CompletedSteps) // ["email", "phone"]

Error Handling

import "errors"

session, err := client.Login.Initiate(ctx, []string{"email"}, "")
if err != nil {
    var apiErr *ma.Error
    if errors.As(err, &apiErr) {
        fmt.Println(apiErr.StatusCode) // 403
        fmt.Println(apiErr.Message)    // "Invalid or inactive API key"
    }
}

Context & Cancellation

All methods accept context.Context for deadline and cancellation support.

// Cancel after 5 seconds
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

health, err := client.Health(ctx)
if err != nil {
    // err will be context.DeadlineExceeded if it times out
    log.Fatal(err)
}