Skip to content

Get started

Quickstart

By the end of this page a person can sign in to your application, you will have a session you can trust on every request, and the same code path will already work for social login, magic links and enterprise SSO.

About 15 minutesNode.js examplesNo credit card

Before you start

You need an application that can serve two routes over HTTPS in production, or over localhost in development: one that starts the sign-in and one that receives the redirect back. Everything else is handled for you.

  • A Paycux account, with an environment you are willing to break
  • A server-side runtime — API keys must never reach the browser
  • A redirect URI you control, registered in the dashboard
1

Environments

Every account starts with two environments: staging and production. They are fully separate — separate API keys, separate users, separate connections, separate webhook endpoints, separate rate limit budgets. Nothing crosses between them, including test data you would rather forget.

EnvironmentKey prefix
Stagingsk_test_
Productionsk_live_

Samples on this site use sk_example_... so that nothing here can ever be a real credential. Your own keys start with sk_test_ or sk_live_.

2

API keys

Two values identify your application: a public client id, which is safe to put in a redirect URL, and a secret key, which is not. Copy both from the dashboard into your environment file — the secret is shown once at creation and never again.

.env.local
1# Public — appears in redirect URLs
2PAYCUX_CLIENT_ID=client_01HQ8ZK3M4N5P6R7S8T9V0W1X2
3
4# Secret — server only, never bundled into client code
5PAYCUX_API_KEY=sk_example_123456789
6
7# Where Paycux sends the user back after sign-in
8PAYCUX_REDIRECT_URI=http://localhost:3000/callback
9
10# 32+ characters, used to encrypt the session cookie
11PAYCUX_COOKIE_PASSWORD=a-long-random-string-you-generate
  • Rotate a key from the dashboard at any time; the old value stops working immediately
  • Keys are scoped to one environment — a staging key cannot read production data
  • Every request is attributed to the key that made it, and appears in your audit log
3

Install the SDK

Pick the client for your language. The rest of this page uses Node.js, but the method names are deliberately the same everywhere.

1npm install @paycux/node

Create the client once and reuse it. It is stateless, safe to share across requests, and reads the secret from the environment if you do not pass one.

lib/paycux.ts
1import Paycux from '@paycux/node';
2
3export const paycux = new Paycux(process.env.PAYCUX_API_KEY, {
4 clientId: process.env.PAYCUX_CLIENT_ID,
5});
4

Redirect to AuthKit

AuthKit is the hosted sign-in experience. You do not build a form, a password reset, an MFA prompt or an SSO discovery screen — you send the person to a URL and get them back with an authorisation code.

app/login/route.ts
1import { redirect } from 'next/navigation';
2import { paycux } from '@/lib/paycux';
3
4export async function GET() {
5 const url = paycux.userManagement.getAuthorizationUrl({
6 provider: 'authkit',
7 redirectUri: process.env.PAYCUX_REDIRECT_URI,
8 clientId: process.env.PAYCUX_CLIENT_ID,
9 });
10
11 redirect(url);
12}

The same call covers every authentication method you have enabled. Turning on Microsoft sign-in or requiring a second factor is a dashboard setting, not a deployment.

5

Handle the callback

The redirect arrives with a single-use code parameter. Exchange it for the authenticated user and a sealed session, then set a cookie and send the person where they were going.

1import { cookies } from 'next/headers';
2import { redirect } from 'next/navigation';
3import { paycux } from '@/lib/paycux';
4
5export async function GET(request: Request) {
6 const code = new URL(request.url).searchParams.get('code');
7
8 const { user, sealedSession } =
9 await paycux.userManagement.authenticateWithCode({
10 code,
11 clientId: process.env.PAYCUX_CLIENT_ID,
12 session: { sealSession: true, cookiePassword: process.env.PAYCUX_COOKIE_PASSWORD },
13 });
14
15 const store = await cookies();
16 store.set('paycux-session', sealedSession, {
17 path: '/', httpOnly: true, secure: true, sameSite: 'lax',
18 });
19
20 console.log('signed in', user.email);
21 redirect('/dashboard');
22}
6

Read the session

On every request, unseal the cookie. If the access token has expired the SDK refreshes it in place and hands you a new sealed value to store. Roles and permissions ride inside the session, so an authorisation check costs no network call.

lib/session.ts
1import { cookies } from 'next/headers';
2import { paycux } from '@/lib/paycux';
3
4export async function currentUser() {
5 const store = await cookies();
6 const sealed = store.get('paycux-session');
7 if (!sealed) return null;
8
9 const session = paycux.userManagement.loadSealedSession({
10 sessionData: sealed.value,
11 cookiePassword: process.env.PAYCUX_COOKIE_PASSWORD,
12 });
13
14 const result = await session.authenticate();
15 if (!result.authenticated) return null;
16
17 // result.permissions comes from the role assigned in this organization
18 return result;
19}

Sessions are per organization. When someone belongs to more than one tenant, switching organization issues a new token with that tenant’s roles — see Role-Based Access Control.

7

Sign out

Clearing your own cookie is not enough — the person is still signed in to the identity provider. Ask for the logout URL so the session ends on both sides.

app/logout/route.ts
1const session = paycux.userManagement.loadSealedSession({
2 sessionData: sealed.value,
3 cookiePassword: process.env.PAYCUX_COOKIE_PASSWORD,
4});
5
6const url = await session.getLogoutUrl();
7
8const store = await cookies();
9store.delete('paycux-session');
10
11redirect(url);

Social login

Social providers are enabled per environment in the dashboard and appear on the AuthKit screen automatically. If you would rather send someone straight to one provider — a “Continue with Google” button of your own — name it in the authorization URL.

app/login/google/route.ts
1const url = paycux.userManagement.getAuthorizationUrl({
2 provider: 'GoogleOAuth',
3 redirectUri: process.env.PAYCUX_REDIRECT_URI,
4 clientId: process.env.PAYCUX_CLIENT_ID,
5});

The callback is identical. Accounts are matched on verified email address, so a person who signed up with a password and later uses Google keeps the same user record.

Magic Auth

Passwordless sign-in with a six-digit code sent by email. Two calls: send the code, then verify it. Useful for invitations, low-friction trials, and anyone who will never remember a password.

magic-auth.ts
1// 1 — send the code
2await paycux.userManagement.createMagicAuth({
3 email: 'alan@foo-corp.example',
4});
5
6// 2 — verify what the person typed
7const { user, sealedSession } =
8 await paycux.userManagement.authenticateWithMagicAuth({
9 code: '493021',
10 email: 'alan@foo-corp.example',
11 clientId: process.env.PAYCUX_CLIENT_ID,
12 session: { sealSession: true, cookiePassword: process.env.PAYCUX_COOKIE_PASSWORD },
13 });

Next steps

Sign-in is the door. These are the rooms behind it — and the reason an enterprise buyer signs the contract.

Add enterprise SSO

One integration for every SAML and OIDC provider your customers run.

Sync their directory

Joiners, movers and leavers arrive from the customer's own systems.

Listen for events

Webhooks for directory changes, sessions and organization membership.

Handle failures well

Status codes, error bodies, retries and rate limits.