CALLBACK_AUTHORIZATION_CODE
, but when I attempt to request the token I get a 400 error.https://<your_kinde_sudomain>.kinde.com/oauth2/token ?client_id=<your_kinde_client_id> &client_secret=<your_kinde_client_secret> &grant_type=authorization_code &redirect_uri=<your_app_redirect_url> &code=<CALLBACK_AUTHORIZATION_CODE>
curl -vv -XPOST -H "Content-Type: application/x-www-form-urlencoded" \ "https://karehero.kinde.com/oauth2/token?client_id=${CLIENT_ID}&client_secret=${CLIENT_SECRET}&grant_type=authorization_code&redirect_uri=http://localhost:3000&code=${CODE}"
var tokenIssuer = "https://<my_domain>.kinde.com" func (k *Kinde) RequestToken(code string) error { // make a request to the token endpoint req, err := http.NewRequest( "POST", fmt.Sprintf("%v/oauth2/token", tokenIssuer), nil, ) if err != nil { return err } // set headers req.Header.Add("Content-Type", "application/x-www-form-urlencoded") // set query params q := req.URL.Query() q.Add("client_id", k.ClientID) q.Add("client_secret", k.ClientSecret) q.Add("grant_type", "authorization_code") q.Add("redirect_uri", "http://localhost:3000") q.Add("code", code) req.URL.RawQuery = q.Encode() // make the request client := &http.Client{} res, err := client.Do(req) if err != nil { return err } defer res.Body.Close() if res.StatusCode != http.StatusOK { return fmt.Errorf("error requesting token: %v", res.Status) } // parse the response body, err := ioutil.ReadAll(res.Body) if err != nil { return err } fmt.Println("Kinde response:", res, string(body)) return nil }
if res.StatusCode != http.StatusOK {
with:error requesting token: 400 Bad Request
fetch(`${<your_domain>}.kinde.com/oauth2/token`, { method: "POST", headers: { "content-type": "application/x-www-form-urlencoded", }, body: new URLSearchParams({ audience: "<auth_domain>/api", grant_type: "authorization_code", client_id: <client_id>, client_secret: <client_secret>, }), })
curl -v -G \ -XPOST \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=authorization_code" \ -d "code=${CODE}" \ -d "client_id=${CLIENT_ID}" \ -d "client_secret=${CLIENT_SECRET}" \ -d "audience=https://${DOMAIN}.kinde.com/api" \ "https://${DOMAIN}.kinde.com/oauth2/token"
* Host <REDACTED>.kinde.com:443 was resolved. * IPv6: (none) * IPv4: 18.133.18.216, 18.132.161.25 * Trying 18.133.18.216:443... * Connected to <REDACTED>.kinde.com (18.133.18.216) port 443 * ALPN: curl offers h2,http/1.1 * TLSv1.3 (OUT), TLS handshake, Client hello (1): * CAfile: /home/jamie/.anaconda3/ssl/cacert.pem * CApath: none * TLSv1.3 (IN), TLS handshake, Server hello (2): * TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8): * TLSv1.3 (IN), TLS handshake, Certificate (11): * TLSv1.3 (IN), TLS handshake, CERT verify (15): * TLSv1.3 (IN), TLS handshake, Finished (20): * TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.3 (OUT), TLS handshake, Finished (20): * SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256 / X25519 / RSASSA-PSS * ALPN: server did not agree on a protocol. Uses default. * Server certificate: * subject: CN=*.kinde.com * start date: Mar 12 00:00:00 2024 GMT * expire date: Apr 11 23:59:59 2025 GMT * subjectAltName: host "<REDACTED>.kinde.com" matched cert's "*.kinde.com" * issuer: C=US; O=Amazon; CN=Amazon RSA 2048 M03 * SSL certificate verify ok. * Certificate level 0: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption * Certificate level 1: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption * Certificate level 2: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption * using HTTP/1.x > POST /oauth2/token?grant_type=authorization_code&client_id=<REDACTED>&client_secret=<REDACTED>&audience=https://<REDACTED>.kinde.com/api HTTP/1.1 > Host: <REDACTED>.kinde.com > User-Agent: curl/8.5.0 > Accept: */* > Content-Type: application/x-www-form-urlencoded > * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4): < HTTP/1.1 400 Bad Request < Date: Fri, 29 Mar 2024 20:52:01 GMT < Content-Length: 0 < Connection: keep-alive < Vary: Origin < * Connection #0 to host <REDACTED>.kinde.com left intact
// set form data form := url.Values{} form.Add("client_id", k.ClientID) form.Add("client_secret", k.ClientSecret) form.Add("grant_type", "authorization_code") form.Add("redirect_uri", "http://localhost:3000/authenticate") form.Add("response_type", "code") form.Add("audience", "https://<REDACTED>.kinde.com/api") form.Add("scope", "openid profile email") form.Add("code", code) req.Body = ioutil.NopCloser(strings.NewReader(form.Encode()))
type KindeTokenResponse struct { AccessToken string `json:"access_token"` ExpiresIn int `json:"expires_in"` IdToken string `json:"id_token"` Scope string `json:"scope"` TokenType string `json:"token_type"` } func (k *Kinde) RequestToken(code string) (KindeTokenResponse, error) { // make a request to the token endpoint req, err := http.NewRequest( "POST", fmt.Sprintf("%v/oauth2/token", tokenIssuer), nil, ) if err != nil { return KindeTokenResponse{}, err } // set headers req.Header.Add("Content-Type", "application/x-www-form-urlencoded") // set form data form := url.Values{} form.Add("client_id", k.ClientID) form.Add("client_secret", k.ClientSecret) form.Add("grant_type", "authorization_code") form.Add("redirect_uri", "http://localhost:3000/authenticate") form.Add("code", code) req.Body = ioutil.NopCloser(strings.NewReader(form.Encode())) // make the request client := &http.Client{} res, err := client.Do(req) if err != nil { return KindeTokenResponse{}, err } defer res.Body.Close() if res.StatusCode != http.StatusOK { return KindeTokenResponse{}, fmt.Errorf( "error requesting token: %v", res.Status, ) } // parse the response var kindeTokenResponse KindeTokenResponse if err := json.NewDecoder(res.Body).Decode(&kindeTokenResponse); err != nil { return KindeTokenResponse{}, err } return kindeTokenResponse, nil }
/oauth2/token
endpoint needs to be POST form data, the doc is a little misleading as it appears that I could perhaps make a curl request (with encoded query parameters) using the format shown in the code example:#!/bin/sh # Set up environment variables export KINDE_DOMAIN="your_kinde_subdomain" export KINDE_CLIENT_ID="your_kinde_client_id" export KINDE_CLIENT_SECRET="your_kinde_client_secret" export APP_REDIRECT_URI="your_app_redirect_url" export CALLBACK_AUTHORIZATION_CODE="CALLBACK_AUTHORIZATION_CODE" # Make the POST request using curl curl -X POST "https://${KINDE_DOMAIN}.kinde.com/oauth2/token" \ -d client_id=${KINDE_CLIENT_ID} \ -d client_secret=${KINDE_CLIENT_SECRET} \ -d grant_type=authorization_code \ -d redirect_uri=${APP_REDIRECT_URI} \ -d code=${CALLBACK_AUTHORIZATION_CODE}
curl -X POST "https://<your_kinde_subdomain>.kinde.com/oauth2/token" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d client_id=<your_kinde_client_id> \ -d client_secret=<your_kinde_client_secret> \ -d grant_type=authorization_code \ -d redirect_uri=<your_app_redirect_url> \ -d code=<CALLBACK_AUTHORIZATION_CODE>