: "${REFLECTIONS_CLIENT_ID:?Set REFLECTIONS_CLIENT_ID before running this example}"
: "${REFLECTIONS_CLIENT_SECRET:?Set REFLECTIONS_CLIENT_SECRET before running this example}"
curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/oauth/introspect' \
-u "$REFLECTIONS_CLIENT_ID:$REFLECTIONS_CLIENT_SECRET" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode 'token=rlt_vSJ3bKIxXFSmOQpwEb0SZrAhc4eOBrwV' \
--data-urlencode 'resource=https://app.reflections.ai/fct_5zba2q8v1m3n7p4r6s9t0wxyhk'import { env, exit } from "node:process";
import { Buffer } from "node:buffer";
const clientId = env.REFLECTIONS_CLIENT_ID;
if (!clientId) throw new Error("Set REFLECTIONS_CLIENT_ID before running this example");
const clientSecret = env.REFLECTIONS_CLIENT_SECRET;
if (!clientSecret) throw new Error("Set REFLECTIONS_CLIENT_SECRET before running this example");
const response = await fetch("https://app.reflections.ai/oauth/introspect", {
method: "POST",
headers: {
Authorization: `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString("base64")}`,
"Content-Type": "application/x-www-form-urlencoded",
},
body: new URLSearchParams({
"token": "rlt_vSJ3bKIxXFSmOQpwEb0SZrAhc4eOBrwV",
"resource": "https://app.reflections.ai/fct_5zba2q8v1m3n7p4r6s9t0wxyhk"
}),
signal: AbortSignal.timeout(30_000),
});
const responseBody = await response.text();
if (!response.ok) {
console.error(`HTTP ${response.status}: ${responseBody}`);
exit(1);
}
console.log(responseBody);
import base64
import os
from urllib.error import HTTPError
from urllib.parse import urlencode
from urllib.request import Request, urlopen
clientId = os.environ["REFLECTIONS_CLIENT_ID"]
if not clientId:
raise ValueError("Set REFLECTIONS_CLIENT_ID before running this example")
clientSecret = os.environ["REFLECTIONS_CLIENT_SECRET"]
if not clientSecret:
raise ValueError("Set REFLECTIONS_CLIENT_SECRET before running this example")
headers = {
"Authorization": "Basic " + base64.b64encode(f"{clientId}:{clientSecret}".encode()).decode(),
"Content-Type": "application/x-www-form-urlencoded",
}
data = urlencode({
"token": "rlt_vSJ3bKIxXFSmOQpwEb0SZrAhc4eOBrwV",
"resource": "https://app.reflections.ai/fct_5zba2q8v1m3n7p4r6s9t0wxyhk",
}).encode("utf-8")
request = Request("https://app.reflections.ai/oauth/introspect",
method="POST", headers=headers, data=data)
try:
with urlopen(request, timeout=30) as response:
print(response.read().decode("utf-8"))
except HTTPError as error:
error_body = error.read().decode("utf-8")
raise RuntimeError(f"HTTP {error.code}: {error_body}") from error
package main
import (
"fmt"
"io"
"net/http"
"net/url"
"os"
"strings"
"time"
)
func main() {
clientId := os.Getenv("REFLECTIONS_CLIENT_ID")
if clientId == "" {
panic("Set REFLECTIONS_CLIENT_ID before running this example")
}
clientSecret := os.Getenv("REFLECTIONS_CLIENT_SECRET")
if clientSecret == "" {
panic("Set REFLECTIONS_CLIENT_SECRET before running this example")
}
form := url.Values{
"token": {"rlt_vSJ3bKIxXFSmOQpwEb0SZrAhc4eOBrwV"},
"resource": {"https://app.reflections.ai/fct_5zba2q8v1m3n7p4r6s9t0wxyhk"},
}
body := strings.NewReader(form.Encode())
request, err := http.NewRequest("POST", "https://app.reflections.ai/oauth/introspect", body)
if err != nil {
panic(err)
}
request.SetBasicAuth(clientId, clientSecret)
request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
client := &http.Client{Timeout: 30 * time.Second}
response, err := client.Do(request)
if err != nil {
panic(err)
}
defer response.Body.Close()
responseBody, err := io.ReadAll(response.Body)
if err != nil {
panic(err)
}
if response.StatusCode < 200 || response.StatusCode >= 300 {
panic(fmt.Sprintf("HTTP %d: %s", response.StatusCode, responseBody))
}
fmt.Print(string(responseBody))
}
{
"active": true,
"token_type": "License",
"permitted": true,
"client_id": "cl_zsyaax01q26b0kmq66g7wt70x9",
"resource": "https://app.reflections.ai/fct_5zba2q8v1m3n7p4r6s9t0wxyhk",
"usage": [
"ai-input"
],
"talent": "tal_9t0wxyhk5zba2q8v1m3n7p4r6s",
"license": "lic_j2fseppybf012bsxt93pv9y4b9",
"livemode": true,
"iat": 1792312320,
"exp": 1792398720
}Introspect a token
Planned contract — unavailable in test and live modes. This operation is a protocol reference, not a callable endpoint. Start with the working sandbox quickstart.
Tells a content host whether an RSL License token is active and whether it covers the
content it was presented for, as OAuth Token Introspection (RFC 7662) and RSL’s Open
License Protocol define. Call it when a client sends Authorization: License <token>, and
serve the content only when active and permitted are both true.
A token is inactive once it expires, and from the moment the license it draws on is
revoked or suspended. Cache an active result for at most 60 seconds. An inactive result
carries only active: false, whatever the reason. Only License tokens can be
introspected: an MCP access token always reads as inactive here.
Authenticate with a confidential client’s client ID and secret, registered with
POST /oauth/register.
: "${REFLECTIONS_CLIENT_ID:?Set REFLECTIONS_CLIENT_ID before running this example}"
: "${REFLECTIONS_CLIENT_SECRET:?Set REFLECTIONS_CLIENT_SECRET before running this example}"
curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/oauth/introspect' \
-u "$REFLECTIONS_CLIENT_ID:$REFLECTIONS_CLIENT_SECRET" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode 'token=rlt_vSJ3bKIxXFSmOQpwEb0SZrAhc4eOBrwV' \
--data-urlencode 'resource=https://app.reflections.ai/fct_5zba2q8v1m3n7p4r6s9t0wxyhk'import { env, exit } from "node:process";
import { Buffer } from "node:buffer";
const clientId = env.REFLECTIONS_CLIENT_ID;
if (!clientId) throw new Error("Set REFLECTIONS_CLIENT_ID before running this example");
const clientSecret = env.REFLECTIONS_CLIENT_SECRET;
if (!clientSecret) throw new Error("Set REFLECTIONS_CLIENT_SECRET before running this example");
const response = await fetch("https://app.reflections.ai/oauth/introspect", {
method: "POST",
headers: {
Authorization: `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString("base64")}`,
"Content-Type": "application/x-www-form-urlencoded",
},
body: new URLSearchParams({
"token": "rlt_vSJ3bKIxXFSmOQpwEb0SZrAhc4eOBrwV",
"resource": "https://app.reflections.ai/fct_5zba2q8v1m3n7p4r6s9t0wxyhk"
}),
signal: AbortSignal.timeout(30_000),
});
const responseBody = await response.text();
if (!response.ok) {
console.error(`HTTP ${response.status}: ${responseBody}`);
exit(1);
}
console.log(responseBody);
import base64
import os
from urllib.error import HTTPError
from urllib.parse import urlencode
from urllib.request import Request, urlopen
clientId = os.environ["REFLECTIONS_CLIENT_ID"]
if not clientId:
raise ValueError("Set REFLECTIONS_CLIENT_ID before running this example")
clientSecret = os.environ["REFLECTIONS_CLIENT_SECRET"]
if not clientSecret:
raise ValueError("Set REFLECTIONS_CLIENT_SECRET before running this example")
headers = {
"Authorization": "Basic " + base64.b64encode(f"{clientId}:{clientSecret}".encode()).decode(),
"Content-Type": "application/x-www-form-urlencoded",
}
data = urlencode({
"token": "rlt_vSJ3bKIxXFSmOQpwEb0SZrAhc4eOBrwV",
"resource": "https://app.reflections.ai/fct_5zba2q8v1m3n7p4r6s9t0wxyhk",
}).encode("utf-8")
request = Request("https://app.reflections.ai/oauth/introspect",
method="POST", headers=headers, data=data)
try:
with urlopen(request, timeout=30) as response:
print(response.read().decode("utf-8"))
except HTTPError as error:
error_body = error.read().decode("utf-8")
raise RuntimeError(f"HTTP {error.code}: {error_body}") from error
package main
import (
"fmt"
"io"
"net/http"
"net/url"
"os"
"strings"
"time"
)
func main() {
clientId := os.Getenv("REFLECTIONS_CLIENT_ID")
if clientId == "" {
panic("Set REFLECTIONS_CLIENT_ID before running this example")
}
clientSecret := os.Getenv("REFLECTIONS_CLIENT_SECRET")
if clientSecret == "" {
panic("Set REFLECTIONS_CLIENT_SECRET before running this example")
}
form := url.Values{
"token": {"rlt_vSJ3bKIxXFSmOQpwEb0SZrAhc4eOBrwV"},
"resource": {"https://app.reflections.ai/fct_5zba2q8v1m3n7p4r6s9t0wxyhk"},
}
body := strings.NewReader(form.Encode())
request, err := http.NewRequest("POST", "https://app.reflections.ai/oauth/introspect", body)
if err != nil {
panic(err)
}
request.SetBasicAuth(clientId, clientSecret)
request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
client := &http.Client{Timeout: 30 * time.Second}
response, err := client.Do(request)
if err != nil {
panic(err)
}
defer response.Body.Close()
responseBody, err := io.ReadAll(response.Body)
if err != nil {
panic(err)
}
if response.StatusCode < 200 || response.StatusCode >= 300 {
panic(fmt.Sprintf("HTTP %d: %s", response.StatusCode, responseBody))
}
fmt.Print(string(responseBody))
}
{
"active": true,
"token_type": "License",
"permitted": true,
"client_id": "cl_zsyaax01q26b0kmq66g7wt70x9",
"resource": "https://app.reflections.ai/fct_5zba2q8v1m3n7p4r6s9t0wxyhk",
"usage": [
"ai-input"
],
"talent": "tal_9t0wxyhk5zba2q8v1m3n7p4r6s",
"license": "lic_j2fseppybf012bsxt93pv9y4b9",
"livemode": true,
"iat": 1792312320,
"exp": 1792398720
}Authorizations
A confidential OAuth client's client_id and client_secret, sent as HTTP Basic
credentials. Register the client with your secret key to receive them; see
POST /oauth/register.
Body
An introspection request, as RFC 7662 defines it.
The token the client presented.
Optional. A License token is an access token.
access_token The content the token was presented for: the facet IRI, or the URL of a file under it.
permitted in the result is about this resource.
Response
Whether the token is active, and what it covers.
Whether a token is active, as RFC 7662 returns it. An inactive token returns only active.
true while the token is unexpired and the license it draws on is active.
Always License.
License Whether the token covers resource. Serve the content only when this and active are both true.
The client the token was issued to.
The facet IRI the token was issued for.
The RSL usage values the token covers, such as ai-input.
The talent whose facet the token covers.
^tal_[0-9a-hjkmnp-tv-z]{26}$The license the token draws on. null when the talent's posture allows the usage without
a license.
^lic_[0-9a-hjkmnp-tv-z]{26}$true for a live-mode token.
Unix seconds when the token was issued.
Unix seconds when the token expires.