Skip to content

Developer

Go

Mint Reqio HS256 identity tokens on a Go server using golang-jwt/jwt/v5.

The snippet below is exactly what the dashboard generates under Project > Settings > Identity when you choose Go. Copy it from the dashboard to get your real project ID and audience URL pre-filled.

Install

go get github.com/golang-jwt/jwt/v5

Mint a token

// go get github.com/golang-jwt/jwt/v5
import (
    "os"
    "time"
    jwt "github.com/golang-jwt/jwt/v5"
)

type reqioClaims struct {
    Email  string         `json:"email"`
    Traits map[string]any `json:"traits"`
    jwt.RegisteredClaims
}

now := time.Now()
claims := reqioClaims{
    Email:  user.Email,
    Traits: map[string]any{"plan": user.Plan, "amount": user.PlanAmount, "interval": user.BillingInterval}, // amount in cents; interval "month" | "year"
    RegisteredClaims: jwt.RegisteredClaims{
        Subject:   user.ID,
        Audience:  jwt.ClaimStrings{"https://reqio.app/p/YOUR_PROJECT_ID"},
        IssuedAt:  jwt.NewNumericDate(now),
        ExpiresAt: jwt.NewNumericDate(now.Add(5 * time.Minute)),
    },
}
token, err := jwt.NewWithClaims(jwt.SigningMethodHS256, claims).
    SignedString([]byte(os.Getenv("REQIO_SECRET")))

Replace YOUR_PROJECT_ID with your project ID, or copy the full snippet from the dashboard where the audience URL is pre-filled.

Environment variable

Set REQIO_SECRET to the signing secret from Project > Settings > Identity > Reveal secret. Store it in an environment variable managed by your deployment platform; never include it in responses.

HTTP handler example

package main

import (
    "net/http"
    "os"
    "text/template"
    "time"

    jwt "github.com/golang-jwt/jwt/v5"
)

type reqioClaims struct {
    Email  string         `json:"email"`
    Traits map[string]any `json:"traits"`
    jwt.RegisteredClaims
}

var tmpl = template.Must(template.ParseFiles("templates/page.html"))

func pageHandler(w http.ResponseWriter, r *http.Request) {
    user := userFromSession(r) // your own session resolution
    if user == nil {
        http.Error(w, "unauthorized", http.StatusUnauthorized)
        return
    }

    now := time.Now()
    claims := reqioClaims{
        Email:  user.Email,
        Traits: map[string]any{"plan": user.Plan, "amount": user.PlanAmountCents, "interval": user.BillingInterval},
        RegisteredClaims: jwt.RegisteredClaims{
            Subject:   user.ID,
            Audience:  jwt.ClaimStrings{os.Getenv("REQIO_AUDIENCE")},
            IssuedAt:  jwt.NewNumericDate(now),
            ExpiresAt: jwt.NewNumericDate(now.Add(5 * time.Minute)),
        },
    }

    token, err := jwt.NewWithClaims(jwt.SigningMethodHS256, claims).
        SignedString([]byte(os.Getenv("REQIO_SECRET")))
    if err != nil {
        http.Error(w, "identity error", http.StatusInternalServerError)
        return
    }

    data := map[string]string{
        "ProjectID":  os.Getenv("REQIO_PROJECT_ID"),
        "ReqioToken": token,
    }
    tmpl.Execute(w, data)
}
<!-- templates/page.html -->
<script
  src="https://reqio.app/widget.js"
  data-project-id="{{ .ProjectID }}"
  data-identity-token="{{ .ReqioToken }}"
  async
></script>

Store the audience URL in REQIO_AUDIENCE so you do not hardcode it.

Pass the token to the widget

For server-rendered HTML, pass the token via data-identity-token:

<script
  src="https://reqio.app/widget.js"
  data-project-id="YOUR_PROJECT_ID"
  data-identity-token="{{ .ReqioToken }}"
  async
></script>

For SPAs where the user authenticates after the initial page load, call window.Reqio.identify() from JavaScript after login:

window.Reqio.identify(token);

Traits reference

| Field | Type | Description | |---|---|---| | plan | string | Plan name on your billing system, e.g. "pro". | | amount | number | Recurring charge as billed, in cents. For annual plans send the full annual total; Reqio divides by 12 to derive the monthly value. | | interval | "month" or "year" | Billing cadence for amount. |

Security

Store REQIO_SECRET in an environment variable and never include it in responses. The JWT is short-lived (5 minutes), signed with HS256, and audience-bound to one Reqio project URL, limiting the damage from a leaked token. The signing secret must remain server-side.