Build with the API

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.

Endpoints
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.json

Register 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.

Scopes
openid
identity
Confirm the user's identity (required for sign-in).
profile
identity
Read the user's name.
email
identity
Read the user's email address and verification state.
api:read
platform
Read the user's OpenCharts content through the REST API.
api:write
platform
Create and edit OpenCharts content on the user's behalf.
api:ai
platform
Run Theo AI work on the user's behalf. Consumes the user's own AI credits.

Identity 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.

The authorize request

Send the user to the authorize URL. They sign in (if needed), review what your app is asking for, and approve. OpenCharts then redirects back to your redirect_uri with a one-time code (valid for 5 minutes) and your state.

GET /oauth/authorize
https://www.opencharts.com/oauth/authorize
  ?client_id=ocapp_your_client_id
  &redirect_uri=https://example.com/auth/callback
  &response_type=code
  &scope=openid profile email api:read api:ai
  &state=random_csrf_token
  &code_challenge=BASE64URL(SHA256(code_verifier))
  &code_challenge_method=S256

Redirect URIs are matched exactly against the list you registered. Users who already approved your app skip the consent screen.

state (up to 2,000 characters) and nonce (up to 512) are echoed back byte-for-byte; longer values are rejected with invalid_request rather than truncated, because a truncated state would silently fail your own CSRF check. If you omit scope, the request defaults to every scope your app is allowed to request: ask for exactly what you need.

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
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
Response
{
  "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.

Theo chat, on the user's behalf
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.

Refreshing
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_token

Revoke 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:

GET /.well-known/openid-configuration (abridged)
{
  "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.

  1. 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 the api:* 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).

  2. 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 email
  3. Paste 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.

  4. 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.

What to choose when the platform asks
Grant / flow
authorization code
response_type=code only. Implicit, hybrid (code id_token) and ID-token-only flows are rejected with unsupported_response_type.
Response mode
query
The code always comes back as query parameters on your redirect URI. form_post and fragment are not supported; platforms that default to form_post must be switched to query.
Client authentication
client_secret_basic or client_secret_post
Both work; basic is the default almost everywhere. private_key_jwt, client_secret_jwt and mTLS are not supported. "None" (no secret) is only for apps registered as public, which then must use PKCE.
PKCE
S256, optional for confidential apps
Leave a platform's PKCE toggle on if it has one. Only S256 is accepted; plain is rejected.
Scopes
openid profile email
Exactly six scopes exist: openid, profile, email, api:read, api:write, api:ai. Anything else (offline_access, address, phone, groups) fails the request with invalid_scope. Refresh tokens are issued without offline_access.
ID token signing
RS256
Verify against the JWKS URL. The token carries iss, sub, aud, exp, iat, auth_time, azp, nonce (when you sent one) plus the identity claims below.
Userinfo
optional
Returns the same claims as the id_token. Turn it on when the platform prefers it; nothing is lost either way.
Signed request objects
off
request and request_uri (JAR) parameters are ignored. Turn off any "signed requests" option (Okta has one) so the platform sends plain query parameters.
Claims you receive
sub, email, email_verified, name, given_name, family_name
sub is the stable user id. email_verified mirrors the user's OpenCharts account and is false until they verify their address. given_name / family_name are split from the single display name: a one-word name has no family_name.

Clerk

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.

  1. 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.

  2. Add a custom provider in Clerk

    Clerk Dashboard > Configure > SSO connections > Add connection > For all users > open the Custom provider tab.

  3. Fill in the connection

    Clerk: custom provider
    Name                 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 work

    Click Add connection. Leave Attribute mapping at its defaults: Clerk reads sub, email, email_verified, given_name and family_name, all of which OpenCharts returns. Type the scopes explicitly: left blank, Clerk sends no scope parameter and the consent screen asks for every scope the app may request, api:* included.

  4. 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 URIs
    Development   https://<slug>.clerk.accounts.dev/v1/oauth_callback
    Production    https://clerk.<your-domain>/v1/oauth_callback
  5. Enable 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.

  6. Trigger it from your own UI (optional)

    Custom sign-in button
    import { 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.

  1. Register the OpenCharts app

    Confidential app, allowed scopes openid profile email. The redirect URI comes from WorkOS in step 3.

  2. 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.

  3. 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.

  4. Fill in the identity provider details

    WorkOS: identity provider details
    Client 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                    on

    Save. The connection turns Active once WorkOS has read the discovery document.

  5. Check the attribute requirements

    WorkOS requires sub and email, and by default also requires given_name and family_name. OpenCharts splits both from the user's single display name, so a user whose name is one word has no family_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.

  6. 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.

  1. Register the OpenCharts app

    Confidential app, allowed scopes openid profile email. Okta's callback is deterministic, so you can register it now:

    Okta redirect URI
    https://{yourOktaDomain}/oauth2/v1/authorize/callback
    (use your custom domain instead of the Okta subdomain if you have one configured)
  2. Add the identity provider

    Admin Console > Security > Identity Providers > Add identity provider > OpenID Connect IdP > Next.

  3. Client details and endpoints

    Okta: OpenID Connect IdP
    Name                     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)
  4. 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 it NONE); OpenCharts reads plain query parameters and does not accept request objects.

  5. 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 idps list to show a button, or link straight to it:

    Direct link
    https://{yourOktaDomain}/oauth2/v1/authorize
      ?idp={idpId}
      &client_id={yourOktaAppClientId}
      &response_type=code
      &scope=openid profile email
      &redirect_uri={yourOktaAppRedirectUri}
      &state=random
      &nonce=random
  6. Profile requirements

    Okta's default user profile requires both first and last name. OpenCharts derives family_name from 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 mark lastName as 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.

  1. 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 example acme.us.auth0.com), or your custom domain if you have enabled one:

    Auth0 redirect URI
    https://{yourTenantDomain}/login/callback
  2. Create the connection

    Auth0 Dashboard > Authentication > Enterprise > OpenID Connect > Create Connection.

  3. Fill in the connection

    Auth0: OpenID Connect connection
    Connection 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 1

    Click Create.

  4. Settings

    On the Settings tab set Scopes to openid profile email (Auth0 always requires openid) 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 puts sub, email, email_verified, name, given_name and family_name in the token, so nothing extra is needed. Save.

  5. Enable it for your applications

    On the Applications tab, toggle the connection on for each application that should offer it.

  6. 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-react
    await 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.

  1. Register the OpenCharts app

    Confidential app with these redirect URIs (opencharts is the provider id you set in step 2):

    Auth.js redirect URIs
    Next.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/opencharts
  2. Configure the provider (Auth.js v5)

    auth.ts
    import 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 other api:* 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.

  3. Keep the OpenCharts tokens (optional)

    When you granted api:* scopes, the first sign-in delivers the access and refresh tokens to the jwt callback. Persist them server-side and refresh with grant_type=refresh_token as described above.

    callbacks
    callbacks: {
      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.

  1. 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 custom authDomain if you use one):

    Firebase redirect URI
    https://<project-id>.firebaseapp.com/__/auth/handler
  2. Add the provider

    Firebase console > Authentication > Sign-in method > Add new provider > OpenID Connect.

  3. Fill in the provider

    Firebase: OpenID Connect provider
    Grant 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.

  4. 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.

    signInWithRedirect works the same way. Firebase fills the user from sub, email, email_verified and name.

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.

  1. Register the OpenCharts app

    Confidential app, allowed scopes openid profile email, redirect URI built from your host, realm and the alias opencharts (older deployments keep the /auth prefix before /realms):

    Keycloak redirect URI
    https://<keycloak-host>/realms/<realm>/broker/opencharts/endpoint
  2. Add the identity provider

    Admin console > select the realm > Identity providers > Add provider > OpenID Connect v1.0.

  3. Fill in the provider

    Keycloak: OpenID Connect v1.0
    Alias                    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.

  4. 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 method S256, and turn on Trust email if brokered emails should count as verified in Keycloak. Save.

  5. Mappers

    Keycloak fills email, first name and last name from email, given_name and family_name automatically, and keys the brokered identity on sub. Add an Attribute Importer mapper only for anything beyond that.

  6. Test

    The realm's login page now shows an OpenCharts button; the account console at https://<host>/realms/<realm>/account uses it. Your clients can skip the chooser by adding kc_idp_hint=opencharts to 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.

  1. Register the OpenCharts app

    Confidential app, allowed scopes openid profile email, and the pool's idpresponse endpoint 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 URI
    https://<your-prefix>.auth.<region>.amazoncognito.com/oauth2/idpresponse
    https://<your-custom-domain>/oauth2/idpresponse
  2. Add 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.)

  3. Fill in the provider

    Cognito: OpenID Connect provider
    Provider 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         -> name

    Cognito fetches the discovery document from the issuer and checks that its issuer field matches exactly, so type it with no trailing slash. sub maps to the Cognito username automatically.

  4. Enable it on the app client

    Applications > App clients > your client > Login pages > Edit > Identity providers > check OpenCharts. Save.

  5. Test

    Open the client's login page (View login page); OpenCharts appears as a provider. To skip the chooser, link straight to it:

    Direct link
    https://<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.

  1. 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.

  2. Point it at discovery

    Discovery URL https://www.opencharts.com/.well-known/openid-configuration or issuer https://www.opencharts.com. If the platform insists on manual endpoints, use the list in the cheat sheet.

  3. Set the flow options

    Authorization code; response mode query (Entra External ID defaults to form_post: switch it); client authentication basic or post with the client secret; PKCE S256 if offered; scopes openid profile email.

  4. Register the callback URL

    Add the platform's callback URL to the OpenCharts app exactly as displayed.

  5. 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.

Symptom, cause, fix
Unknown or disabled app
error card on opencharts.com
The client_id is mistyped, belongs to a deleted app, or comes from a different OpenCharts app than the one you meant. Copy it again from Developers > OAuth apps and make sure dev and prod platform instances point at the same app.
redirect_uri is not registered
error card on opencharts.com
The platform's callback URL is not on the app, or differs by a character: https vs http, a trailing slash, or a dev-instance URL while the prod instance is calling. Add the URL exactly as the platform displays it; registering both dev and prod is normal.
invalid_scope
returned to the platform
The platform asked for a scope OpenCharts does not have (offline_access, address, phone and groups are the usual culprits) or one the app is not allowed to request. Set the platform's scopes to openid profile email and check the app's allowed scopes. Refresh tokens are issued without offline_access.
unsupported_response_type
returned to the platform
The platform chose an implicit, hybrid or ID-token flow. Pick the authorization code flow: Back Channel in Auth0, Code flow in Firebase, response_type=code everywhere else.
Platform says the code is missing
platform-side error
The platform expected the code as a POST (form_post) or in the URL fragment. OpenCharts always returns it as query parameters; set the platform's response mode to query.
invalid_client
token exchange
The secret is wrong or was rotated, or the client type does not match: a public app must not send a secret and a confidential app must. Paste the current secret; after rotating it in OpenCharts, update every platform instance that uses it.
invalid_grant
token exchange
The code expired (5 minutes), was already used, the redirect_uri in the token request differs from the authorize request, or the PKCE verifier does not match. Start the sign-in again; if it repeats, look for a proxy or rewrite changing the callback URL between the two requests.
Consent screen asks for API access
unexpected scopes
The platform sent no scope parameter, so the request defaulted to every scope the app may request, api:* included. Set openid profile email explicitly in the platform (Clerk leaves scopes blank by default), or remove the api:* scopes from the app's allowed scopes.
Missing last name
given_name / family_name
Both come from the user's single OpenCharts display name; a one-word name has no family_name and an empty name has neither. Ask the user to set a first and last name in OpenCharts settings, or make the last-name attribute optional in the platform (WorkOS environment attributes, Okta profile editor).
Rejected for email_verified
Clerk enterprise, policy-based platforms
email_verified mirrors the OpenCharts account and is false until the user verifies their email address. Have the user verify it in OpenCharts, then sign in again.
Signed request or JWT error
Okta
Signed requests is on. OpenCharts reads plain query parameters; turn it off (request_signature_scope NONE).
Sign-in stalls on the consent page
opencharts.com
After 8 seconds a manual Continue link appears; after 10 seconds a Reload button. Use them. If the platform then reports that the attempt expired (Clerk does), start again from the platform: its attempt has its own clock.
Works in dev, fails in prod
platform instances
Most platforms treat production as a separate instance with its own connection and callback URL. Configure the connection again there and register the production callback URL on the same OpenCharts app (or on a dedicated production app).

The 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.