The module needs Go 1.22 or later and has no dependencies.
go get github.com/Keyd-Solutions/nexafon/packages/server-goToken endpoint
Section titled “Token endpoint”func nexafonToken(w http.ResponseWriter, r *http.Request) { u := signedInUser(r) if u == nil { w.WriteHeader(http.StatusUnauthorized) return } if !mayUseNexafon(u) { w.WriteHeader(http.StatusForbidden) return } // "" signs with NEXAFON_SECRET_KEY (sk_test_… or sk_live_…), which never leaves this server. // Nexafon links a first sign-in to the member with this email only when it is verified: never send true for // an address your app has not confirmed, or whoever sets a member's email on your app acts as that member. token, err := nexafon.CreateUserToken("", nexafon.User{ ID: u.ID, Name: u.Name, Role: "agent", Email: u.Email, EmailVerified: u.EmailVerified, }) if err != nil { http.Error(w, "", http.StatusInternalServerError) return } w.Header().Set("Content-Type", "text/plain") w.Header().Set("Cache-Control", "no-store") _, _ = io.WriteString(w, token)}CreateUserToken(secretKey, user, opts...): an empty secretKey reads NEXAFON_SECRET_KEY; nexafon.ExpiresIn(d)
sets the lifetime (at most 10 minutes).
Webhook receiver
Section titled “Webhook receiver”func nexafonWebhook(w http.ResponseWriter, r *http.Request) { // The raw body, exactly as received: parsing it first changes the bytes the signature covers. body, err := io.ReadAll(http.MaxBytesReader(w, r.Body, 1<<20)) if err != nil { w.WriteHeader(http.StatusBadRequest) return } ev, err := nexafon.VerifyWebhook(r.Header, body, os.Getenv("NEXAFON_WEBHOOK_SECRET")) if errors.Is(err, nexafon.ErrInvalidWebhook) { w.WriteHeader(http.StatusBadRequest) return } if err != nil { w.WriteHeader(http.StatusInternalServerError) return } // Deliveries can repeat: skip an ev.ID you have already handled. log.Println(ev.Type, ev.ID) w.WriteHeader(http.StatusNoContent)}Pass nexafon.AlsoSecret(previous) while you rotate the secret. The sample is a complete net/http server
(go run .).