Sign in with OpenDunes from Go — get an API key on your user's wallet with the PKCE flow.
With Sign in with OpenDunes, your app gets an API key on its user's wallet, with the user's approval. The flow is PKCE; the whole of it is on OAuth PKCE. The exchange needs no key of its own.
buf := make([]byte, 48)
rand.Read(buf) // crypto/rand
codeVerifier := base64.RawURLEncoding.EncodeToString(buf) // keep it until the exchange
sum := sha256.Sum256([]byte(codeVerifier))
codeChallenge := base64.RawURLEncoding.EncodeToString(sum[:])
q := url.Values{}
q.Set("callback_url", "http://localhost:8765/callback")
q.Set("code_challenge", codeChallenge)
q.Set("code_challenge_method", "S256")
q.Set("key_label", "Souk Bot CLI")
authURL := "https://opendunes.com/auth?" + q.Encode()
// open authURL in the user's browsercallback_url is HTTPS, or HTTP on localhost or 127.0.0.1 — for a CLI tool or a local app. The user signs in, may set a spending cap on the key, and chooses Authorize or Deny. On Authorize they come back to your callback with ?code=…; on Deny, with error=access_denied.
body, _ := json.Marshal(map[string]string{
"code": code, // from the callback's query string
"code_verifier": codeVerifier,
"code_challenge_method": "S256",
})
resp, err := http.Post("https://opendunes.com/v1/auth/keys", "application/json", bytes.NewReader(body))
// resp body: { "key": "sk-…", "user_id": "…" }A code lives ten minutes and trades once. An unknown, expired or used code, or a verifier that does not match, is a 400.
Configure the client with the user's key in place of yours. Every request on it spends the user's wallet. The user sees the key among their own and can cap, pause or delete it.