curl --request POST \
--url https://api.next.orenda.finance/v2/auth/sso/token-exchange \
--header 'Content-Type: application/json' \
--header 'x-program-id: <x-program-id>' \
--data '
{
"idToken": "eyJraWQiOi...JWT...id...redacted"
}
'import requests
url = "https://api.next.orenda.finance/v2/auth/sso/token-exchange"
payload = { "idToken": "eyJraWQiOi...JWT...id...redacted" }
headers = {
"x-program-id": "<x-program-id>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-program-id': '<x-program-id>', 'Content-Type': 'application/json'},
body: JSON.stringify({idToken: 'eyJraWQiOi...JWT...id...redacted'})
};
fetch('https://api.next.orenda.finance/v2/auth/sso/token-exchange', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.next.orenda.finance/v2/auth/sso/token-exchange",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'idToken' => 'eyJraWQiOi...JWT...id...redacted'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-program-id: <x-program-id>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.next.orenda.finance/v2/auth/sso/token-exchange"
payload := strings.NewReader("{\n \"idToken\": \"eyJraWQiOi...JWT...id...redacted\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-program-id", "<x-program-id>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.next.orenda.finance/v2/auth/sso/token-exchange")
.header("x-program-id", "<x-program-id>")
.header("Content-Type", "application/json")
.body("{\n \"idToken\": \"eyJraWQiOi...JWT...id...redacted\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.next.orenda.finance/v2/auth/sso/token-exchange")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-program-id"] = '<x-program-id>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"idToken\": \"eyJraWQiOi...JWT...id...redacted\"\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"idToken": "eyJhbGciOi...JWT...id...redacted",
"accessToken": "eyJhbGciOi...JWT...access...redacted",
"refreshToken": "eyJjdHkiOi...JWT...refresh...redacted",
"expiresIn": 3600,
"hasMfa": false,
"hasPasskey": false
}
}Exchange an ID token (v2)
Native token exchange. Your app signs in to your identity provider with PKCE and posts the JWT it received: an access token minted for the Orenda audience we agreed, or the id_token if we registered your native app’s client id. We check iss, aud, exp and the signature against what we registered for your program, then return Orenda tokens for the matching user. Each token can be exchanged once. The first exchange for a sub creates and links the user; it needs a verified email in the token. Refresh with POST /v2/auth/refresh, not at your provider. Enabled per program; see the guide.
curl --request POST \
--url https://api.next.orenda.finance/v2/auth/sso/token-exchange \
--header 'Content-Type: application/json' \
--header 'x-program-id: <x-program-id>' \
--data '
{
"idToken": "eyJraWQiOi...JWT...id...redacted"
}
'import requests
url = "https://api.next.orenda.finance/v2/auth/sso/token-exchange"
payload = { "idToken": "eyJraWQiOi...JWT...id...redacted" }
headers = {
"x-program-id": "<x-program-id>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-program-id': '<x-program-id>', 'Content-Type': 'application/json'},
body: JSON.stringify({idToken: 'eyJraWQiOi...JWT...id...redacted'})
};
fetch('https://api.next.orenda.finance/v2/auth/sso/token-exchange', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.next.orenda.finance/v2/auth/sso/token-exchange",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'idToken' => 'eyJraWQiOi...JWT...id...redacted'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-program-id: <x-program-id>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.next.orenda.finance/v2/auth/sso/token-exchange"
payload := strings.NewReader("{\n \"idToken\": \"eyJraWQiOi...JWT...id...redacted\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-program-id", "<x-program-id>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.next.orenda.finance/v2/auth/sso/token-exchange")
.header("x-program-id", "<x-program-id>")
.header("Content-Type", "application/json")
.body("{\n \"idToken\": \"eyJraWQiOi...JWT...id...redacted\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.next.orenda.finance/v2/auth/sso/token-exchange")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-program-id"] = '<x-program-id>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"idToken\": \"eyJraWQiOi...JWT...id...redacted\"\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"idToken": "eyJhbGciOi...JWT...id...redacted",
"accessToken": "eyJhbGciOi...JWT...access...redacted",
"refreshToken": "eyJjdHkiOi...JWT...refresh...redacted",
"expiresIn": 3600,
"hasMfa": false,
"hasPasskey": false
}
}Headers
Identifies the program. Can also be sent as the programId query parameter.
Body
The JWT your identity provider issued to your native app: the access token for the Orenda audience, or the ID token.
1