# Send the person's browser to this URL.
AUTHORIZE_URL='https://app.reflections.ai/oauth/authorize?response_type=code&client_id=cl_064fvt404z82ymdspje0ggaztt&redirect_uri=https%3A%2F%2Fnorthlight.example%2Foauth%2Freflections%2Fcallback&scope=files%3Awrite+checks%3Awrite+generations%3Awrite+usage%3Awrite&state=Rk0OaU_G8bRVUyv9&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&code_challenge_method=S256'const authorizeUrl = new URL("https://app.reflections.ai/oauth/authorize");
authorizeUrl.search = new URLSearchParams({
"response_type": "code",
"client_id": "cl_064fvt404z82ymdspje0ggaztt",
"redirect_uri": "https://northlight.example/oauth/reflections/callback",
"scope": "files:write checks:write generations:write usage:write",
"state": "Rk0OaU_G8bRVUyv9",
"code_challenge": "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM",
"code_challenge_method": "S256"
}).toString();
// Send the person's browser to authorizeUrl.toString().
console.log(authorizeUrl.toString());
from urllib.parse import urlencode
authorize_url = "https://app.reflections.ai/oauth/authorize" + "?" + urlencode({
"response_type": "code",
"client_id": "cl_064fvt404z82ymdspje0ggaztt",
"redirect_uri": "https://northlight.example/oauth/reflections/callback",
"scope": "files:write checks:write generations:write usage:write",
"state": "Rk0OaU_G8bRVUyv9",
"code_challenge": "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM",
"code_challenge_method": "S256",
})
# Send the person's browser to authorize_url.
print(authorize_url)
package main
import (
"fmt"
"net/url"
)
func main() {
query := url.Values{
"response_type": {"code"},
"client_id": {"cl_064fvt404z82ymdspje0ggaztt"},
"redirect_uri": {"https://northlight.example/oauth/reflections/callback"},
"scope": {"files:write checks:write generations:write usage:write"},
"state": {"Rk0OaU_G8bRVUyv9"},
"code_challenge": {"E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM"},
"code_challenge_method": {"S256"},
}
authorizeURL := "https://app.reflections.ai/oauth/authorize" + "?" + query.Encode()
// Send the person's browser to authorizeURL.
fmt.Println(authorizeURL)
}
<string>{
"type": "https://docs.reflections.ai/errors/rate_limited",
"title": "Too many requests",
"status": 429,
"code": "rate_limited",
"request_id": "req_8f2k4m6p8r0t2v4x6z8b0d2f4h"
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"code": "invalid_request",
"request_id": "<string>",
"detail": "<string>",
"param": "<string>",
"doc_url": "<string>"
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"code": "invalid_request",
"request_id": "<string>",
"detail": "<string>",
"param": "<string>",
"doc_url": "<string>"
}Authorize a client
Planned contract — unavailable in test and live modes. This operation is a protocol reference, not a callable endpoint. Start with the working sandbox quickstart.
The page where a person approves an OAuth client. Send the person’s browser here; your server never calls it. A licensee approves a platform’s connection, and an agent’s user approves an MCP client. The person signs in to Reflections, chooses test or live mode, and sees the client’s name and the scopes it asks for.
Reflections then redirects to redirect_uri. After an approval the query carries code,
state and iss; after a decline it carries error=access_denied, state and iss.
Check that state matches and that iss is https://app.reflections.ai. A code works once
and expires after 10 minutes. A platform redeems it at
POST /v1/connections with its secret
key; every other client redeems it at
POST /oauth/token.
PKCE with S256 is required for every client. When client_id is unknown or
redirect_uri is not one of the client’s registered URIs, Reflections shows an error page
and does not redirect, so a code never reaches an address the client did not register.
Public: the person signs in on the page, and no key is sent.
# Send the person's browser to this URL.
AUTHORIZE_URL='https://app.reflections.ai/oauth/authorize?response_type=code&client_id=cl_064fvt404z82ymdspje0ggaztt&redirect_uri=https%3A%2F%2Fnorthlight.example%2Foauth%2Freflections%2Fcallback&scope=files%3Awrite+checks%3Awrite+generations%3Awrite+usage%3Awrite&state=Rk0OaU_G8bRVUyv9&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&code_challenge_method=S256'const authorizeUrl = new URL("https://app.reflections.ai/oauth/authorize");
authorizeUrl.search = new URLSearchParams({
"response_type": "code",
"client_id": "cl_064fvt404z82ymdspje0ggaztt",
"redirect_uri": "https://northlight.example/oauth/reflections/callback",
"scope": "files:write checks:write generations:write usage:write",
"state": "Rk0OaU_G8bRVUyv9",
"code_challenge": "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM",
"code_challenge_method": "S256"
}).toString();
// Send the person's browser to authorizeUrl.toString().
console.log(authorizeUrl.toString());
from urllib.parse import urlencode
authorize_url = "https://app.reflections.ai/oauth/authorize" + "?" + urlencode({
"response_type": "code",
"client_id": "cl_064fvt404z82ymdspje0ggaztt",
"redirect_uri": "https://northlight.example/oauth/reflections/callback",
"scope": "files:write checks:write generations:write usage:write",
"state": "Rk0OaU_G8bRVUyv9",
"code_challenge": "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM",
"code_challenge_method": "S256",
})
# Send the person's browser to authorize_url.
print(authorize_url)
package main
import (
"fmt"
"net/url"
)
func main() {
query := url.Values{
"response_type": {"code"},
"client_id": {"cl_064fvt404z82ymdspje0ggaztt"},
"redirect_uri": {"https://northlight.example/oauth/reflections/callback"},
"scope": {"files:write checks:write generations:write usage:write"},
"state": {"Rk0OaU_G8bRVUyv9"},
"code_challenge": {"E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM"},
"code_challenge_method": {"S256"},
}
authorizeURL := "https://app.reflections.ai/oauth/authorize" + "?" + query.Encode()
// Send the person's browser to authorizeURL.
fmt.Println(authorizeURL)
}
<string>{
"type": "https://docs.reflections.ai/errors/rate_limited",
"title": "Too many requests",
"status": 429,
"code": "rate_limited",
"request_id": "req_8f2k4m6p8r0t2v4x6z8b0d2f4h"
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"code": "invalid_request",
"request_id": "<string>",
"detail": "<string>",
"param": "<string>",
"doc_url": "<string>"
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"code": "invalid_request",
"request_id": "<string>",
"detail": "<string>",
"param": "<string>",
"doc_url": "<string>"
}Query Parameters
Always code.
code The client's ID: a platform's platform.client_id from
GET /v1/account, a client_id from
POST /oauth/register, or the HTTPS URL of
the client's metadata document.
Where Reflections sends the person back. It must equal one of the client's registered redirect URIs.
Space-separated scopes. A platform asks for connection scopes, and an MCP client for MCP scopes. Ask only for what you use.
An unguessable value you keep with the person's session. It comes back unchanged;
reject a redirect whose state you did not send.
16 - 512The PKCE challenge, BASE64URL(SHA-256(code_verifier)) without padding.
43Always S256.
S256 The resource the token will be used at, as RFC 8707 defines. MCP clients send
https://app.reflections.ai/mcp. Platforms leave it out.
Response
Redirects to redirect_uri. After an approval the query carries code, state and
iss. After a decline or a request Reflections cannot accept, it carries error, an
optional error_description, state and iss. error is access_denied (the person
declined), invalid_scope (a scope the client may not ask for),
invalid_request (a missing or malformed parameter, including PKCE),
unsupported_response_type, server_error or temporarily_unavailable.