Sign in with OpenCharts
Add OAuth sign-in to your platform and call the API on your users' behalf.
How it works
OpenCharts is a standard OAuth 2.1 / OpenID Connect provider. Put a "Sign in with OpenCharts" button on your product, and after the user approves your app you receive tokens that both identify the user and, with the API scopes, let your platform call the OpenCharts API on their behalf: Theo chat, image and video generation, projects, sheets, boards, and more.
The flow is the authorization code grant with PKCE. No implicit grant, no password grant. Confidential (server-side) apps authenticate with a client secret; public apps (SPA, mobile) must use PKCE with the S256 method.
Authorize https://www.opencharts.com/oauth/authorize
Token https://www.opencharts.com/api/oauth/token
User info https://www.opencharts.com/api/oauth/userinfo
Revocation https://www.opencharts.com/api/oauth/revoke
Discovery https://www.opencharts.com/.well-known/openid-configuration
JWKS https://www.opencharts.com/.well-known/jwks.jsonRegister an app
Create an app under Developers > OAuth apps. You choose the app's name, its exact redirect URIs, and the scopes it may request. Confidential apps receive a client secret exactly once, at creation; store it server-side like any other secret.
Optionally upload a logo (PNG, JPG or WebP, up to 2 MB). It appears next to your app's name on the sign-in and consent screens and in users' Authorized apps; without one, users see a letter monogram. Square marks fill the tile; wordmarks are fitted inside it without cropping.
openididentityprofileidentityemailidentityapi:readplatformapi:writeplatformapi:aiplatformIdentity is free; API scopes follow the user's plan
Any OpenCharts user can sign in to your app, on every plan. Calls made with the api:* scopes run as the user and follow the same plan gate as the rest of the REST API: the USER needs a plan with API access (Pro or Teams), otherwise those calls return 403.
Exchanging the code
Your backend exchanges the code for tokens at the token endpoint. Authenticate with HTTP Basic (client_id:client_secret) or with body parameters; public clients send only their client_id plus the PKCE code_verifier.
curl -X POST https://www.opencharts.com/api/oauth/token \
-u "ocapp_your_client_id:ocs_your_client_secret" \
-d grant_type=authorization_code \
-d code=occ_the_code_from_the_redirect \
-d redirect_uri=https://example.com/auth/callback \
-d code_verifier=your_pkce_verifier{
"access_token": "oca_...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "ocr_...",
"scope": "openid profile email api:read api:ai",
"id_token": "eyJhbGciOiJSUzI1NiIs..."
}The id_token is an RS256 JWT (verify it against the JWKS URL) carrying sub, and, per the granted scopes, name, given_name, family_name, email, and email_verified. You can also call GET /api/oauth/userinfo with the access token for the same claims.
Calling the API as the user
The access token is a Bearer credential for the whole REST API (and the MCP server), limited to the scopes the user granted. Work runs as the user: their projects, their credits, their plan limits. Calls appear in both your app's and the user's usage analytics.
curl -X POST https://www.opencharts.com/api/v1/chat \
-H "Authorization: Bearer oca_the_users_access_token" \
-H "Content-Type: application/json" \
-d '{"message": "Summarize my latest project", "stream": false}'Refresh & revocation
Access tokens live 1 hour. Refresh tokens live 60 days and ROTATE: each refresh returns a new pair and retires the old refresh token. Reusing a retired refresh token revokes the whole session family, so store the newest pair atomically.
curl -X POST https://www.opencharts.com/api/oauth/token \
-u "ocapp_your_client_id:ocs_your_client_secret" \
-d grant_type=refresh_token \
-d refresh_token=ocr_the_latest_refresh_tokenRevoke tokens you no longer need at POST /api/oauth/revoke (revoking a refresh token revokes its whole family). Users can also revoke your app at any time from their OpenCharts settings, after which every token your app holds for them stops working.
OIDC discovery & libraries
Standard OpenID Connect libraries, and every hosted identity platform in the sections below, configure themselves from the discovery document. Most stacks need only the issuer URL (or the discovery URL) plus your client id and secret. The document advertises exactly what this server does, and nothing it does not:
{
"issuer": "https://www.opencharts.com",
"authorization_endpoint": "https://www.opencharts.com/oauth/authorize",
"token_endpoint": "https://www.opencharts.com/api/oauth/token",
"userinfo_endpoint": "https://www.opencharts.com/api/oauth/userinfo",
"revocation_endpoint": "https://www.opencharts.com/api/oauth/revoke",
"jwks_uri": "https://www.opencharts.com/.well-known/jwks.json",
"response_types_supported": ["code"],
"response_modes_supported": ["query"],
"grant_types_supported": ["authorization_code", "refresh_token"],
"code_challenge_methods_supported": ["S256"],
"token_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_post", "none"],
"scopes_supported": ["openid", "profile", "email", "api:read", "api:write", "api:ai"],
"claims_supported": ["sub", "name", "given_name", "family_name", "email", "email_verified"],
"id_token_signing_alg_values_supported": ["RS256"]
}The issuer is https://www.opencharts.com with no trailing slash. Libraries that validate iss strictly (Cognito, Keycloak, openid-client) need it typed exactly that way. The cheat sheet below lists the values every platform shares; the platform sections walk through each vendor's screens.
Keep the secret server-side
The client secret must never ship in a browser or mobile bundle. Browser-only apps should register as a PUBLIC client and rely on PKCE instead of a secret. Every hosted platform in this guide exchanges the code from its own servers, so they all use a confidential app.
Connecting an identity platform
Clerk, WorkOS, Okta, Auth0, Firebase, Keycloak, Cognito and any other OpenID Connect relying party are all wired up the same way: register an app here, paste three values into the platform, paste the platform's callback URL back into the app, sign in once. This section is the shared recipe; each platform section below maps it onto that vendor's screens.
Register a confidential app in OpenCharts
Developers > OAuth apps > New app. Choose Confidential (the platform exchanges the code from its servers). Allowed scopes:
openid,profile,email. Leave theapi:*scopes off unless the platform will also call the OpenCharts API for the user. Copy the client id (ocapp_...) and the client secret (ocs_..., shown once).Paste the OpenCharts values into the platform
Platforms that take a discovery (well-known) URL need only the first line plus your credentials. Platforms that want endpoints typed by hand take the rest.
OpenCharts values (identical for every platform)Discovery / well-known URL https://www.opencharts.com/.well-known/openid-configuration Issuer https://www.opencharts.com Authorization endpoint https://www.opencharts.com/oauth/authorize Token endpoint https://www.opencharts.com/api/oauth/token Userinfo endpoint https://www.opencharts.com/api/oauth/userinfo JWKS URL https://www.opencharts.com/.well-known/jwks.json Client ID ocapp_... (Developers > OAuth apps) Client secret ocs_... (shown once at creation) Scopes openid profile emailPaste the platform's callback URL into the OpenCharts app
Each platform shows a fixed redirect / callback URL once the connection exists. Add it to the app's redirect URIs exactly as displayed: same scheme, host, path, and trailing slash (or none). Development and production instances usually have different URLs; register both.
Test with a real OpenCharts account
Sign in through the platform's hosted page. The OpenCharts consent screen appears once and lists the three identity scopes; approve it, and later sign-ins skip straight through.
Grant / flowauthorization codeResponse modequeryClient authenticationclient_secret_basic or client_secret_postPKCES256, optional for confidential appsScopesopenid profile emailID token signingRS256UserinfooptionalSigned request objectsoffClaims you receivesub, email, email_verified, name, given_name, family_nameClerk
Clerk connects to OpenCharts as a custom OAuth provider (a social-style connection every user can pick) or as a custom OIDC enterprise connection scoped to specific email domains. Both configure themselves from the discovery URL. The social route is on every Clerk plan and is the one to start with.
Register the OpenCharts app
Developers > OAuth apps: confidential app, allowed scopes
openid profile email. Keep the client id and secret handy; the redirect URI comes from Clerk in step 4.Add a custom provider in Clerk
Clerk Dashboard > Configure > SSO connections > Add connection > For all users > open the Custom provider tab.
Fill in the connection
Clerk: custom providerName OpenCharts Key opencharts (immutable; the strategy becomes oauth_custom_opencharts) Discovery Endpoint https://www.opencharts.com/.well-known/openid-configuration Client ID ocapp_... Client Secret ocs_... Scopes openid profile email Use PKCE on (S256) or off; both workClick Add connection. Leave Attribute mapping at its defaults: Clerk reads
sub,email,email_verified,given_nameandfamily_name, all of which OpenCharts returns. Type the scopes explicitly: left blank, Clerk sends noscopeparameter and the consent screen asks for every scope the app may request,api:*included.Copy the Authorized redirect URI into OpenCharts
The connection page now shows an Authorized redirect URI. Add it to the app's redirect URIs verbatim. Development and production instances have different URIs, and the production instance is a separate connection you configure again before launch:
Clerk redirect URIsDevelopment https://<slug>.clerk.accounts.dev/v1/oauth_callback Production https://clerk.<your-domain>/v1/oauth_callbackEnable the connection and test it
Flip Enable connection. Your Account Portal sign-in page (
https://<slug>.accounts.dev/sign-in) and the<SignIn />component now show a Continue with OpenCharts button. Sign in with an OpenCharts account, approve the consent screen once, and Clerk creates the user with their name and email filled in.Trigger it from your own UI (optional)
Custom sign-in buttonimport { useSignIn } from "@clerk/nextjs"; export function SignInWithOpenCharts() { const { signIn } = useSignIn(); return ( <button type="button" onClick={() => signIn?.authenticateWithRedirect({ strategy: "oauth_custom_opencharts", redirectUrl: "/sso-callback", redirectUrlComplete: "/", }) } > Continue with OpenCharts </button> ); } // app/sso-callback/page.tsx renders <AuthenticateWithRedirectCallback />The strategy is
oauth_custom_followed by the Key you chose in step 3.
Enterprise connection (specific email domains)
Add connection > For specific domains or organizations > OpenID Connect > Custom OIDC Provider. Give it a name, a key and the email domain (or organization), copy its Authorized redirect URI into the OpenCharts app, then fill in the same discovery URL, client id, client secret and scopes before enabling it. Enterprise connections are a paid Clerk feature and only accept users whose email_verified is true, so the OpenCharts account's email must be verified.
If a sign-in attempt stalls
Start it again from Clerk. Clerk's own attempt expires after a few minutes and it will not exchange a code minted after that, even though the OpenCharts side succeeded.
WorkOS
WorkOS models OpenCharts as a generic OpenID Connect SSO connection on an organization. Users you send to that connection (or whose email domain belongs to the organization) sign in with OpenCharts; the rest of AuthKit is unchanged.
Register the OpenCharts app
Confidential app, allowed scopes
openid profile email. The redirect URI comes from WorkOS in step 3.Create the connection
WorkOS Dashboard > Organizations > pick the organization > Single Sign-On > Configure manually (or Create connection) > choose OpenID Connect as the identity provider > Create Connection.
Copy the Redirect URI into OpenCharts
Under Service Provider Details copy the Redirect URI and add it to the app. It is unique per connection and per WorkOS environment (staging and production differ), so never hardcode it: copy what the dashboard shows.
Fill in the identity provider details
WorkOS: identity provider detailsClient ID ocapp_... Client Secret ocs_... Discovery Endpoint https://www.opencharts.com/.well-known/openid-configuration Advanced (the defaults are right) Authentication method Client secret basic (Client secret POST also works; Private key JWT does not) ID token signing RS256 Use userinfo endpoint optional PKCE onSave. The connection turns Active once WorkOS has read the discovery document.
Check the attribute requirements
WorkOS requires
subandemail, and by default also requiresgiven_nameandfamily_name. OpenCharts splits both from the user's single display name, so a user whose name is one word has nofamily_name. Either ask those users to set a first and last name in OpenCharts, or make last name optional in your environment's identity provider attribute settings.Start a sign-in
AuthKit (User Management)import { WorkOS } from "@workos-inc/node"; const workos = new WorkOS(process.env.WORKOS_API_KEY); const authorizationUrl = workos.userManagement.getAuthorizationUrl({ clientId: process.env.WORKOS_CLIENT_ID!, redirectUri: "https://your-app.com/callback", // Either target the connection directly... connectionId: "conn_01H...", // ...or let WorkOS pick it from the organization: // organizationId: "org_01H...", });The classic SSO API works the same way with
workos.sso.getAuthorizationUrl({ connection }). Organization admins can also complete steps 2 to 4 themselves through the Admin Portal.
Okta
Okta adds OpenCharts as an OpenID Connect identity provider (inbound federation): Okta is the relying party, OpenCharts authenticates the user, and Okta creates or links the Okta user. Works on Classic Engine and Identity Engine.
Register the OpenCharts app
Confidential app, allowed scopes
openid profile email. Okta's callback is deterministic, so you can register it now:Okta redirect URIhttps://{yourOktaDomain}/oauth2/v1/authorize/callback (use your custom domain instead of the Okta subdomain if you have one configured)Add the identity provider
Admin Console > Security > Identity Providers > Add identity provider > OpenID Connect IdP > Next.
Client details and endpoints
Okta: OpenID Connect IdPName OpenCharts Client ID ocapp_... Client secret ocs_... Scopes openid profile email Issuer https://www.opencharts.com Authorization endpoint https://www.opencharts.com/oauth/authorize Token endpoint https://www.opencharts.com/api/oauth/token JWKS endpoint https://www.opencharts.com/.well-known/jwks.json Userinfo endpoint https://www.opencharts.com/api/oauth/userinfo (optional)Authentication settings
IdP username:
idpuser.email. Match against: Okta username or email. If no match: create a new user (JIT) to let OpenCharts users self-register, or redirect to the Okta sign-in page to allow only existing Okta users.Two settings must stay at values OpenCharts supports. Client authentication: client secret (choose "Use PKCE" only if your OpenCharts app is registered as public). Signed requests: off. Okta can wrap the authorize request in a signed JWT (the API field is
request_signature_scope; keep itNONE); OpenCharts reads plain query parameters and does not accept request objects.Make the IdP reachable
Finish creating the IdP, then give users a way to reach it: add an IdP routing rule (Security > Identity Providers > Routing rules) so matching sign-ins go to OpenCharts, add the IdP id to the Sign-In Widget's
idpslist to show a button, or link straight to it:Direct linkhttps://{yourOktaDomain}/oauth2/v1/authorize ?idp={idpId} &client_id={yourOktaAppClientId} &response_type=code &scope=openid profile email &redirect_uri={yourOktaAppRedirectUri} &state=random &nonce=randomProfile requirements
Okta's default user profile requires both first and last name. OpenCharts derives
family_namefrom the display name, so a one-word name leaves it empty and JIT creation fails. Ask those users to set a first and last name in OpenCharts, or marklastNameas not required in Directory > Profile Editor > User (default).
Auth0
Auth0 treats OpenCharts as an OpenID Connect enterprise connection. Once the connection is enabled on an application, Universal Login shows a button for it, or routes matching email domains to it automatically.
Register the OpenCharts app
Confidential app, allowed scopes
openid profile email, and the Auth0 callback as the redirect URI. Use your tenant domain exactly as the dashboard shows it (for exampleacme.us.auth0.com), or your custom domain if you have enabled one:Auth0 redirect URIhttps://{yourTenantDomain}/login/callbackCreate the connection
Auth0 Dashboard > Authentication > Enterprise > OpenID Connect > Create Connection.
Fill in the connection
Auth0: OpenID Connect connectionConnection name opencharts (immutable; used as the connection= parameter) Issuer URL https://www.opencharts.com/.well-known/openid-configuration (Auth0 fetches the document and shows a green check) Client ID ocapp_... Type Back Channel (Front Channel is the implicit flow and is not supported) Client Secret ocs_... Callback URL shown here; it must match what you registered in step 1Click Create.
Settings
On the Settings tab set Scopes to
openid profile email(Auth0 always requiresopenid) and decide whether to sync profile attributes on every login. Auth0 reads identity claims from the id_token itself and does not call userinfo; OpenCharts putssub,email,email_verified,name,given_nameandfamily_namein the token, so nothing extra is needed. Save.Enable it for your applications
On the Applications tab, toggle the connection on for each application that should offer it.
Login experience and test
On Login Experience, turn on Display connection as a button (with a display name and logo) for a "Continue with OpenCharts" button, or add Identity Provider domains so users typing an email at those domains are routed automatically. Test with the connection's Try button, or from your app:
auth0-spa-js / auth0-reactawait auth0.loginWithRedirect({ authorizationParams: { connection: "opencharts" }, });
Auth.js / NextAuth
If you own the backend, Auth.js is the shortest path: one custom OIDC provider object and no extra platform. Auth.js verifies the id_token against the JWKS, handles PKCE and state, and hands you the profile.
Register the OpenCharts app
Confidential app with these redirect URIs (
openchartsis the provideridyou set in step 2):Auth.js redirect URIsNext.js, production https://your-app.com/api/auth/callback/opencharts Next.js, local dev http://localhost:3000/api/auth/callback/opencharts Other Auth.js runtimes https://your-app.com/auth/callback/openchartsConfigure the provider (Auth.js v5)
auth.tsimport NextAuth from "next-auth"; export const { handlers, auth, signIn, signOut } = NextAuth({ providers: [ { id: "opencharts", name: "OpenCharts", type: "oidc", issuer: "https://www.opencharts.com", clientId: process.env.OPENCHARTS_CLIENT_ID, clientSecret: process.env.OPENCHARTS_CLIENT_SECRET, checks: ["pkce", "state"], authorization: { params: { scope: "openid profile email" }, }, }, ], });Add
api:read(or the otherapi:*scopes) to the scope string only when your app will call the OpenCharts API for the user; they must also be on the app's allowed scopes.Keep the OpenCharts tokens (optional)
When you granted
api:*scopes, the first sign-in delivers the access and refresh tokens to thejwtcallback. Persist them server-side and refresh withgrant_type=refresh_tokenas described above.callbackscallbacks: { async jwt({ token, account }) { if (account?.provider === "opencharts") { token.openchartsAccessToken = account.access_token; token.openchartsRefreshToken = account.refresh_token; token.openchartsExpiresAt = account.expires_at; } return token; }, },
NextAuth v4
v4 has no type: "oidc". Use type: "oauth" with wellKnown: "https://www.opencharts.com/.well-known/openid-configuration", idToken: true, checks: ["pkce", "state"], the same authorization.params.scope, and a profile(profile) callback returning { id: profile.sub, name: profile.name, email: profile.email }.
Firebase Authentication
Firebase Authentication accepts OpenCharts as an OpenID Connect provider once the project is upgraded to Firebase Authentication with Identity Platform (a one-click upgrade in the console; OIDC providers are not on the legacy tier). Use the code flow: Firebase's ID-token flow is the implicit grant, which OpenCharts does not issue.
Register the OpenCharts app
Confidential app, allowed scopes
openid profile email, and Firebase's auth handler as the redirect URI (the provider form shows the exact value; substitute your customauthDomainif you use one):Firebase redirect URIhttps://<project-id>.firebaseapp.com/__/auth/handlerAdd the provider
Firebase console > Authentication > Sign-in method > Add new provider > OpenID Connect.
Fill in the provider
Firebase: OpenID Connect providerGrant type Code flow Name opencharts (the provider id becomes oidc.opencharts) Client ID ocapp_... Issuer (URL) https://www.opencharts.com Client secret ocs_...Save. Firebase fetches the discovery document and JWKS from the issuer.
Sign in from the client
Web (modular SDK)import { getAdditionalUserInfo, getAuth, OAuthProvider, signInWithPopup, } from "firebase/auth"; const provider = new OAuthProvider("oidc.opencharts"); provider.addScope("profile"); provider.addScope("email"); const result = await signInWithPopup(getAuth(), provider); const credential = OAuthProvider.credentialFromResult(result); // credential?.idToken is the OpenCharts id_token; // getAdditionalUserInfo(result)?.profile holds its claims.signInWithRedirectworks the same way. Firebase fills the user fromsub,email,email_verifiedandname.
Keycloak
Keycloak brokers OpenCharts as an OpenID Connect v1.0 identity provider in a realm. The alias you choose is baked into the redirect URI, so pick it first.
Register the OpenCharts app
Confidential app, allowed scopes
openid profile email, redirect URI built from your host, realm and the aliasopencharts(older deployments keep the/authprefix before/realms):Keycloak redirect URIhttps://<keycloak-host>/realms/<realm>/broker/opencharts/endpointAdd the identity provider
Admin console > select the realm > Identity providers > Add provider > OpenID Connect v1.0.
Fill in the provider
Keycloak: OpenID Connect v1.0Alias opencharts (shown in the Redirect URI at the top of the form) Display name OpenCharts Use discovery endpoint on Discovery endpoint https://www.opencharts.com/.well-known/openid-configuration Client authentication Client secret sent as basic auth (or: Client secret sent as post) Client ID ocapp_... Client Secret ocs_...Click Add.
Settings after creation
Under Advanced settings set Scopes to
openid profile email, keep Validate signatures on with Use JWKS URL on (imported from discovery), enable PKCE with methodS256, and turn on Trust email if brokered emails should count as verified in Keycloak. Save.Mappers
Keycloak fills email, first name and last name from
email,given_nameandfamily_nameautomatically, and keys the brokered identity onsub. Add an Attribute Importer mapper only for anything beyond that.Test
The realm's login page now shows an OpenCharts button; the account console at
https://<host>/realms/<realm>/accountuses it. Your clients can skip the chooser by addingkc_idp_hint=openchartsto their login URL.
Amazon Cognito
A Cognito user pool federates to OpenCharts as an OpenID Connect identity provider. Cognito's hosted (managed) login shows the provider, exchanges the code, and mints its own tokens for your app.
Register the OpenCharts app
Confidential app, allowed scopes
openid profile email, and the pool'sidpresponseendpoint as the redirect URI. The domain is the one configured under the pool's domain settings (a Cognito prefix domain or your custom domain):Cognito redirect URIhttps://<your-prefix>.auth.<region>.amazoncognito.com/oauth2/idpresponse https://<your-custom-domain>/oauth2/idpresponseAdd the identity provider
Cognito console > User pools > your pool > Authentication > Social and external providers > Add identity provider > OpenID Connect (OIDC). (Older console: Sign-in experience > Federated identity provider sign-in.)
Fill in the provider
Cognito: OpenID Connect providerProvider name OpenCharts (no spaces; this is the identity_provider value) Client ID ocapp_... Client secret ocs_... Authorized scopes openid profile email Attribute request method GET Setup method Auto fill through issuer URL Issuer URL https://www.opencharts.com Map attributes email -> email given_name -> given_name family_name -> family_name name -> nameCognito fetches the discovery document from the issuer and checks that its
issuerfield matches exactly, so type it with no trailing slash.submaps to the Cognito username automatically.Enable it on the app client
Applications > App clients > your client > Login pages > Edit > Identity providers > check OpenCharts. Save.
Test
Open the client's login page (View login page); OpenCharts appears as a provider. To skip the chooser, link straight to it:
Direct linkhttps://<your-domain>/oauth2/authorize ?identity_provider=OpenCharts &client_id=<cognitoAppClientId> &response_type=code &scope=openid+email+profile &redirect_uri=<yourAppCallback>
Any other OIDC platform
Anything that can act as an OpenID Connect relying party follows the same recipe: Microsoft Entra External ID, Ping, OneLogin, FusionAuth, Ory, or openid-client, Passport, Spring Security and django-allauth in your own backend. When the platform offers a "custom OpenID Connect" or "generic OIDC" provider type, that is the one to pick.
Pick the generic OpenID Connect provider type
Never a vendor template (Google, GitHub) with OpenCharts URLs pasted in: templates hardcode scopes and claim shapes that will not match.
Point it at discovery
Discovery URL
https://www.opencharts.com/.well-known/openid-configurationor issuerhttps://www.opencharts.com. If the platform insists on manual endpoints, use the list in the cheat sheet.Set the flow options
Authorization code; response mode
query(Entra External ID defaults toform_post: switch it); client authentication basic or post with the client secret; PKCES256if offered; scopesopenid profile email.Register the callback URL
Add the platform's callback URL to the OpenCharts app exactly as displayed.
Map the claims
sub(stable id),email,email_verified,name,given_name,family_name.
Platforms with a fixed provider list
Some hosted auth products (Supabase Auth, for example) only offer a fixed menu of social providers and no generic OIDC option. Terminate the OpenCharts flow yourself instead (the Auth.js section above, or openid-client on your server), verify the id_token against the JWKS, and create the platform session from the verified claims.
Troubleshooting
Fatal problems (an unknown app or an unregistered callback) render an error card on opencharts.com and never redirect. Everything after that is sent back to your platform as error + error_description query parameters, or returned by the token endpoint as JSON.
Unknown or disabled apperror card on opencharts.comredirect_uri is not registerederror card on opencharts.cominvalid_scopereturned to the platformunsupported_response_typereturned to the platformPlatform says the code is missingplatform-side errorinvalid_clienttoken exchangeinvalid_granttoken exchangeConsent screen asks for API accessunexpected scopesMissing last namegiven_name / family_nameRejected for email_verifiedClerk enterprise, policy-based platformsSigned request or JWT errorOktaSign-in stalls on the consent pageopencharts.comWorks in dev, fails in prodplatform instancesThe error card and the error_description your platform receives name the exact check that failed. Quote them when you ask for help; never paste a code, a token or a client secret.