Skip to content

Authentication

The Go SDK supports manual web-based login (request token → access token) and fully automated login with TOTP.

Prerequisites

Before authenticating, ensure you have:

  • Valid Arrow user credentials
  • Registered redirect URL in the Developer Apps section
  • Your appID and appSecret from the Trading API section
  • Static IP registered (mandatory per SEBI Circular)

Authentication Methods

Method 1: Web-based Login (Manual)

Redirect users to Arrow's login page, then exchange the callback request-token.

package main

import (
    "fmt"
    "log"

    "github.com/arrow-trade/go-arrow/arrow"
)

func main() {
    client := arrow.NewClient("YOUR_APP_ID", "YOUR_APP_SECRET")

    // Prints https://app.arrow.trade/app/login?appId=<appID> and reads the token from stdin
    client.Login()

    fmt.Println("Access token:", client.GetToken())
}

If you already have the request token (for example from your OAuth callback), skip the stdin prompt:

token, err := client.Authenticate("request_token_from_callback")
if err != nil {
    log.Fatal(err)
}
fmt.Println("Access token:", token)

Authenticate SHA256-hashes appId:appSecret:request-token and POSTs to /auth/app/authenticate-token on https://edge.arrow.trade. It sends both checkSum and checksum in the JSON body.

Login URL query key

Login() prints ?appId= (lowercase d). Build the same URL yourself with fmt.Sprintf("https://app.arrow.trade/app/login?appId=%s", appID).

Callback URL

After successful login, Arrow redirects to your registered URL with:

  • request-token: Temporary authentication token
  • checksum: SHA256 hash for verification

Method 2: Automated Login (TOTP)

AutoLogin runs the full credential + TOTP + token-exchange flow. The app secret is taken from NewClient, not passed again.

Parameter Required Description
username Arrow user ID
password Account password
totpSecret Base32 TOTP secret
if err := client.AutoLogin("YOUR_USER_ID", "YOUR_PASSWORD", "YOUR_TOTP_SECRET"); err != nil {
    log.Fatal(err)
}
fmt.Println("Logged in. Token:", client.GetToken())

Flow:

  1. POST https://api.arrow.trade/auth/app/login
  2. Generate a 6-digit TOTP (30s period, SHA1)
  3. POST https://edge.arrow.trade/auth/validate-2fa
  4. Parse request-token from the redirect URL
  5. Authenticate(requestToken) — stores Token on the client

TOTP Secret

The totpSecret is the base32 encoded secret used to generate time-based one-time passwords. You can go to the profile page and copy the TOTP secret if enabled. If not enabled, log out of the current session and click on forgot password and complete the flow.

Session Management

Get Current Token

token := client.GetToken()

Set Token Manually

Reuse a valid token from a previous session (still within 24 hours):

client.SetToken("your_existing_access_token")

Clear Session

There is no InvalidateSession helper. Clear the token:

client.SetToken("")

Token Lifecycle

Aspect Details
Validity 24 hours from generation
After expiry New login required — refresh tokens are not supported
Storage Store securely; never expose in client-side code

Token Expiration

Access tokens expire after 24 hours due to regulatory compliance. Implement a re-login path in long-running processes.

Authentication Response

Authenticate returns the access token string and updates client.Config. The wire payload looks like:

{
  "status": "success",
  "data": {
    "name": "ABHISHEK JAIN",
    "token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9...",
    "userId": "AJ0001"
  }
}
Field Type Description
name string User's full name
token string JWT access token
userId string Unique user identifier

User Information

After authentication, retrieve profile and limits:

user, err := client.GetUserDetails()
if err != nil {
    log.Fatal(err)
}
fmt.Println("Logged in as:", user.Data.Name)
fmt.Println("Exchanges:", user.Data.Exchanges)

limits, err := client.GetLimits()
if err != nil {
    log.Fatal(err)
}
fmt.Println("Usable margin:", limits.Data.Margin["usableMargin"])

Wrapped user and limits

GetUserDetails returns *User with Data + Status (use user.Data.Name). GetLimits is the same (limits.Data.Margin). Positions, holdings, and order book return unwrapped slices.

Error Handling

if err := client.AutoLogin(userID, password, totpSecret); err != nil {
    log.Printf("Authentication failed: %v", err)
    return
}

Common Errors

Error Cause Solution
Invalid checksum Incorrect SHA256 generation Verify appId:appSecret:request-token format
Token expired Request token timeout Restart authentication flow
Invalid credentials Wrong user ID or password Verify credentials
Invalid TOTP Incorrect or expired OTP Check TOTP secret and system time sync

Security Best Practices

Security Notice

  • Never expose appSecret in client-side code
  • Never commit credentials to version control
  • Always use environment variables for sensitive data
  • Always use HTTPS for all API communications

Environment Variables Example

package main

import (
    "log"
    "os"

    "github.com/arrow-trade/go-arrow/arrow"
)

func main() {
    client := arrow.NewClient(os.Getenv("ARROW_APP_ID"), os.Getenv("ARROW_APP_SECRET"))

    if err := client.AutoLogin(
        os.Getenv("ARROW_USER_ID"),
        os.Getenv("ARROW_PASSWORD"),
        os.Getenv("ARROW_TOTP_SECRET"),
    ); err != nil {
        log.Fatal(err)
    }
}

Complete Example

package main

import (
    "fmt"
    "log"
    "os"

    "github.com/arrow-trade/go-arrow/arrow"
)

func initializeClient() (*arrow.Client, error) {
    client := arrow.NewClient(os.Getenv("ARROW_APP_ID"), os.Getenv("ARROW_APP_SECRET"))

    if err := client.AutoLogin(
        os.Getenv("ARROW_USER_ID"),
        os.Getenv("ARROW_PASSWORD"),
        os.Getenv("ARROW_TOTP_SECRET"),
    ); err != nil {
        return nil, fmt.Errorf("login: %w", err)
    }

    user, err := client.GetUserDetails()
    if err != nil {
        return nil, fmt.Errorf("user details: %w", err)
    }
    fmt.Println("Logged in as:", user.Data.Name)
    return client, nil
}

func main() {
    client, err := initializeClient()
    if err != nil {
        log.Fatal(err)
    }
    _ = client
}