Getting Started: New Calimatic App

Quick start guide for integrating a new Calimatic application with the Calimatic Auth platform.

This guide is for Category 1 apps: greenfield Calimatic products with few or no users that need to integrate with centralized authentication from day one.


Prerequisites

  • Access to the Calimatic Auth admin dashboard, or credentials for the dynamic registration endpoint
  • Your application's callback URL(s) (production + localhost for development)
  • Node.js 18+ (for Next.js/React examples)
  • Familiarity with OAuth 2.0 / OpenID Connect concepts

1. Register Your App Client

You need an OAuth client registration before your app can authenticate users. There are two ways to get one.

Option A: Request from Calimatic Admin

Ask a Calimatic Auth administrator to create your app client via the admin dashboard at https://auth.calimatic.com/admin/app-clients. They will provide you with:

  • client_id (prefixed cca_)
  • client_secret (prefixed ccas_, shown only once)

Option B: Dynamic Registration

Call the registration endpoint directly:

curl -X POST https://auth.calimatic.com/api/v1/oidc/register \
  -H "Content-Type: application/json" \
  -d '{
    "client_name": "My New App",
    "redirect_uris": [
      "https://myapp.calimatic.com/auth/callback",
      "http://localhost:3001/auth/callback"
    ],
    "grant_types": ["authorization_code", "refresh_token"],
    "scope": "openid profile email organization permissions"
  }'

Response (201 Created):

{
  "client_id": "cca_aBcDeFgHiJkL...",
  "client_secret": "ccas_xYzAbCdEfGhI...",
  "client_secret_expires_at": 0,
  "client_name": "My New App",
  "redirect_uris": [
    "https://myapp.calimatic.com/auth/callback",
    "http://localhost:3001/auth/callback"
  ],
  "grant_types": ["authorization_code", "refresh_token"],
  "token_endpoint_auth_method": "client_secret_post",
  "scope": "openid profile email organization permissions"
}

Store the client_secret securely. It is returned exactly once and cannot be retrieved again.

Configure Redirect URIs

Redirect URIs are validated with exact string match. Register all environments:

EnvironmentExample URI
Productionhttps://myapp.calimatic.com/auth/callback
Staginghttps://staging-myapp.calimatic.com/auth/callback
Developmenthttp://localhost:3001/auth/callback

Choose Your Scopes

ScopePurposeRecommended For
openidRequired for OIDCAll apps
profileName, avatarAll apps
emailEmail addressAll apps
organizationOrg ID, memberships, user typeCalimatic apps that need org context
permissionsPlatform permissions, rolesApps that enforce platform-level permissions

For most Calimatic apps, use: openid profile email organization

Apps that need permission-gated features should add permissions.


2. Configure OIDC with Next.js

The recommended integration uses NextAuth.js v5 with the Calimatic OIDC provider.

Install NextAuth

npm install next-auth

Create src/auth.ts

import NextAuth from "next-auth";

export const { handlers, signIn, signOut, auth } = NextAuth({
  providers: [
    {
      id: "calimatic",
      name: "Calimatic",
      type: "oidc",
      issuer: "https://auth.calimatic.com",
      clientId: process.env.CALIMATIC_CLIENT_ID!,
      clientSecret: process.env.CALIMATIC_CLIENT_SECRET!,
      authorization: {
        params: {
          scope: "openid profile email organization",
          code_challenge_method: "S256",
        },
      },
      profile(profile) {
        return {
          id: profile.sub,
          name: profile.name,
          email: profile.email,
          image: profile.picture,
        };
      },
    },
  ],
  callbacks: {
    async jwt({ token, account, profile }) {
      if (account) {
        token.accessToken = account.access_token;
        token.refreshToken = account.refresh_token;
        token.expiresAt = account.expires_at;
        token.idToken = account.id_token;
      }
      if (profile) {
        token.organizationId = profile.organization_id;
        token.organizationMemberships = profile.organization_memberships;
        token.userType = profile.user_type;
      }
      return token;
    },
    async session({ session, token }) {
      session.accessToken = token.accessToken as string;
      session.user.organizationId = token.organizationId as string;
      session.user.organizationMemberships = token.organizationMemberships;
      session.user.userType = token.userType as string;
      return session;
    },
  },
});

Create the Route Handler

src/app/api/auth/[...nextauth]/route.ts:

import { handlers } from "@/auth";
export const { GET, POST } = handlers;

Set Environment Variables

.env.local:

CALIMATIC_CLIENT_ID=cca_your_client_id
CALIMATIC_CLIENT_SECRET=ccas_your_client_secret
NEXTAUTH_URL=http://localhost:3001
NEXTAUTH_SECRET=generate-a-random-secret-here

Use in Server Components

import { auth } from "@/auth";
import { redirect } from "next/navigation";

export default async function Dashboard() {
  const session = await auth();

  if (!session) {
    redirect("/api/auth/signin");
  }

  return (
    <div>
      <h1>Welcome, {session.user.name}</h1>
      <p>Organization: {session.user.organizationId}</p>
    </div>
  );
}

Use in Client Components

"use client";
import { useSession, signIn, signOut } from "next-auth/react";

export function AuthButton() {
  const { data: session, status } = useSession();

  if (status === "loading") return <div>Loading...</div>;

  if (session) {
    return (
      <div>
        <p>Signed in as {session.user.email}</p>
        <button onClick={() => signOut()}>Sign out</button>
      </div>
    );
  }

  return (
    <button onClick={() => signIn("calimatic")}>
      Sign in with Calimatic
    </button>
  );
}

For the full integration guide including manual OAuth flows, React SPA integration, and backend/server-side examples, see the Integration Guide.


3. Create Your Organization

Before provisioning users, your app needs to create its organization on the auth platform. Organizations originate at the app level -- when a customer subscribes, your app registers their org.

Create Organization via API

curl -X POST https://auth.calimatic.com/api/v1/organizations \
  -H "Content-Type: application/json" \
  -H "x-client-id: cca_your_client_id" \
  -H "x-client-secret: ccas_your_client_secret" \
  -d '{
    "name": "Acme Corp",
    "slug": "acme-corp",
    "type": "customer"
  }'
const response = await fetch("https://auth.calimatic.com/api/v1/organizations", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "x-client-id": process.env.CALIMATIC_CLIENT_ID!,
    "x-client-secret": process.env.CALIMATIC_CLIENT_SECRET!,
  },
  body: JSON.stringify({
    name: "Acme Corp",
    slug: "acme-corp",
    type: "customer",
  }),
});

const { data: org } = await response.json();
// org.id is the organization UUID to use when provisioning users

The endpoint is idempotent -- if the slug already exists, it returns the existing organization (409 status) with its ID. Your app is automatically enabled for any organization it creates.

Required Permission

Your app client needs the org:manage permission. This is separate from org:users:manage (needed for user provisioning).


4. Provision Users with the Provisioning API

New apps typically need to create or invite users into their organization. Use the Provisioning API to do this programmatically.

Single User Provisioning

curl -X POST https://auth.calimatic.com/api/v1/users/provision \
  -H "Content-Type: application/json" \
  -H "x-client-id: cca_your_client_id" \
  -H "x-client-secret: ccas_your_client_secret" \
  -d '{
    "email": "jane@school.edu",
    "firstName": "Jane",
    "lastName": "Smith",
    "organizationId": "org-uuid-here",
    "role": "member",
    "sendInviteEmail": true
  }'
const response = await fetch("https://auth.calimatic.com/api/v1/users/provision", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "x-client-id": process.env.CALIMATIC_CLIENT_ID!,
    "x-client-secret": process.env.CALIMATIC_CLIENT_SECRET!,
  },
  body: JSON.stringify({
    email: "jane@school.edu",
    firstName: "Jane",
    lastName: "Smith",
    organizationId: "org-uuid-here",
    role: "member",
    sendInviteEmail: true,
  }),
});

const { data } = await response.json();
// data.userId, data.keycloakUserId, data.email, data.isNewUser

Bulk Provisioning

For creating multiple users at once (up to 500 per batch):

curl -X POST https://auth.calimatic.com/api/v1/users/provision/bulk \
  -H "Content-Type: application/json" \
  -H "x-client-id: cca_your_client_id" \
  -H "x-client-secret: ccas_your_client_secret" \
  -d '{
    "users": [
      { "email": "user1@school.edu", "firstName": "User", "lastName": "One" },
      { "email": "user2@school.edu", "firstName": "User", "lastName": "Two" }
    ],
    "defaultOrganizationId": "org-uuid-here",
    "sendInviteEmails": true
  }'

For full API reference, see the User Management API.


5. Auto-Licensing

When your app client invites a user via the Provisioning API, the platform automatically assigns a license for your application. No extra configuration is needed.

How It Works

The platform follows a three-layer licensing model:

LayerWhatHow
App RegistrationRegister your app as an OAuth clientAdmin creates via dashboard, or dynamic registration
Org EnablementEnable the app for a specific organizationAdmin creates organization_app_access record with isEnabled: true
User AssignmentGrant a user access to the appuser_app_licenses record created automatically when user is provisioned by the app

Auto-Assignment Rules

  1. App client calls the provisioning API: The calling app's identity (requestor.application) is automatically included in the license list. The user gets a license for the calling app.

  2. Explicit applications array: If you pass an applications array, only those apps (that are enabled on the organization) are assigned.

  3. No apps specified and no app client context: The user receives licenses for all apps enabled on the organization.

Verify a User's License

After OIDC login, call the resolve endpoint to check if the user has a license for your app:

curl "https://auth.calimatic.com/api/v1/users/resolve?email=jane@school.edu" \
  -H "x-client-id: cca_your_client_id" \
  -H "x-client-secret: ccas_your_client_secret"

The response includes a hasLicense boolean when called with app client credentials, plus the full list of all the user's licenses.


6. Integration Checklist

Use this checklist to verify your OIDC integration is complete:

  • Client registrationclient_id and client_secret obtained and stored securely
  • Redirect URIs — All environments registered (production, staging, localhost)
  • Login Page URL — Set loginUrl on your app client so the platform can redirect users to your login page (e.g., after email verification)
  • Organization created — Your app's organization exists on the auth platform (via POST /api/v1/organizations)
  • Scopes — Selected appropriate scopes for your app's needs
  • OIDC config — NextAuth (or manual OIDC) configured and connecting to https://auth.calimatic.com
  • Login flow — Users can log in and are redirected back to your app with a valid session
  • Organization context — If using organization scope, verify organizationId is present in the session
  • User provisioning — App can create/invite users via the Provisioning API
  • Auto-licensing — Provisioned users receive a license for your app
  • Token refresh — Access tokens are refreshed before expiry (NextAuth handles this automatically)
  • Logout — Sign-out clears the session and redirects to the Calimatic end-session endpoint
  • Webhook subscriptions — Subscribe to user.deleted, user.suspended, user.updated, license.revoked events to keep your app in sync
  • User lifecycle sync — When users/orgs are deleted in your app, notify the auth platform via the API
  • Error handlinginvalid_token, access_denied, and other OAuth errors are handled gracefully
  • Test with real users — End-to-end test with at least one user going through login, consent, and accessing your app

For the complete integration checklist covering all integration methods (OIDC, Headless API, SDK), email verification, MFA, security, and more, see the Integration Checklist.


Next Steps