TypeScript SDK for integrating web apps and Node services with Base IDP.
npm install @squareexp/base-idpGet credentials from Base client registration, not from local guesses. The SDK now treats Base as the source of truth for redirect URIs, scopes, audience, auth methods, and requested claims. Your app only needs the Base client identity and, if the client is confidential, the secret:
BASE_IDP_CLIENT_IDBASE_IDP_SECRET(server-side only, if the client is confidential)
The SDK ships with a bootstrap command that prints the env block and registration payload for a client, and can optionally POST the registration to Base:
npx base-idp init \
--client-id console-gateway \
--display-name "Base Console" \
--product console \
--app-domain console.cloud.squareexp.com \
--redirect-uri http://localhost:3010/api/auth/callback \
--allowed-redirect-uris http://localhost:3010/api/auth/callback \
--allowed-origins http://localhost:3010 \
--allowed-scopes "openid profile console:manage" \
--allowed-auth-methods password,magic_link \
--requested-claims email,profileAdd --post --admin-token <token> to register directly through the Base admin API.
This package is also emitted as a release artifact when we cut an SDK release. The release bundle contains the packed npm tarball plus matching Go, Rust, and Laravel artifacts for the same Base IdP version.
To generate the local release bundle:
./scripts/release-base-idp-sdks.sh sdk-v1.0.0To download a published bundle:
gh release download sdk-v1.0.0 --repo <owner>/<repo>Server-side:
BASE_IDP_CLIENT_ID=<your-client-id>
BASE_IDP_SECRET=<your-client-secret-if-confidential>The SDK resolves the issuer automatically from the current runtime environment:
- localhost/dev runtimes use
http://localhost:8080 - production defaults to
https://authlayer.square.com
BASE_IDP_CLIENT_SECRET is still accepted as a legacy alias at runtime.
The SDK discovers redirect URIs, allowed scopes, and audience from Base, so apps do not need to duplicate those lists in env.
Vite/browser-safe:
VITE_BASE_IDP_CLIENT_ID=<public-client-id>Never expose BASE_IDP_SECRET or BASE_IDP_CLIENT_SECRET in browser bundles.
Use these surfaces when your app server talks to Base:
createNextBaseIdpAuth(...)for Next.js App Router login and callback handlersBaseIdpServerClientfor direct token exchange, refresh, and verificationcreateExpressMiddleware(...)for Express / rawhttproute protectioncreateNestBaseIdpGuard(...)for NestJS guards
If your service only needs to validate a bearer token, use the server client’s verifyAccessToken(...) method and keep the Base environment plus the client identifier in env. If the service also exchanges codes or refreshes tokens, provide the client secret too. Redirect URIs and scopes are resolved from Base client registration.
import { createReactBaseIdpAuth } from "@squareexp/base-idp/react";
const auth = createReactBaseIdpAuth({
clientId: "crm-web",
});
export function LoginButton() {
return <button {...auth.buttonProps({ state: "/dashboard" })}>Continue with Base IdP</button>;
}import { createNextBaseIdpAuth } from "@squareexp/base-idp/next";
const baseIdp = createNextBaseIdpAuth({
clientId: process.env.BASE_IDP_CLIENT_ID!,
clientSecret: process.env.BASE_IDP_SECRET!,
});
export const GET = baseIdp.login;Callback route:
export const GET = baseIdp.callback;import { createExpressMiddleware, baseIdpConfigFromNodeEnv } from "@squareexp/base-idp/node";
const requireBaseIdpAuth = createExpressMiddleware(baseIdpConfigFromNodeEnv(), {
requiredScope: "crm:read",
attachUser: true,
});import { BaseIdpServerClient } from "@squareexp/base-idp/server";
const baseIdp = new BaseIdpServerClient({
clientId: process.env.BASE_IDP_CLIENT_ID!,
});
const principal = await baseIdp.verifyAccessToken(accessToken);This SDK fully supports local validation of PASETO v4.public tokens using discovered and cached Ed25519 keys, ensuring secure offline checking of audience, issuer, expiry, and scopes.