Base IdP

Base IdP

Getting Started

Quickstart

Scaffold a working Base IdP app for any stack with one command.

The fastest way to get Base IdP running in your project is the scaffolder. You pick a stack, you paste your keys, and the CLI writes a starter that already works. No copy-pasting snippets out of a wiki. No guessing which env vars you need. The first time you run it should take about a minute.

This page walks through that minute, then explains what was generated so you can pick the file apart and adapt it.

Before you start

You need two things:

  1. A registered app. Open Square Experience Cloud, create an app, and copy the client id. If your app runs login on a server you also need the secret. See Create an App for the full flow.
  2. Node 20 or newer. The CLI ships with the TypeScript SDK and runs through npx. There is nothing to install globally.

That is it. No other tooling, no extra accounts.

The one command

npx base-idp create

Run it with no flags and the CLI prompts you for the stack, the client id, and a redirect URI. If you would rather skip the prompts, pass them inline:

npx base-idp create \
  --stack flutter \
  --client-id sq_live_yourapp \
  --redirect-uri "myapp://auth/callback"

For a confidential server you also pass the secret. Keep this command in your shell history rather than a Makefile if you want — the secret should never end up in version control.

npx base-idp create \
  --stack nextjs-fullstack \
  --client-id sq_live_web \
  --client-secret sqk_your_secret

Listing every stack

If you are not sure which template fits, list them first.

npx base-idp create --list
Available stacks:
  flutter            Flutter (mobile, public)
  react-native       React Native / Expo (mobile, public)
  swiftui            SwiftUI (iOS, public)
  nextjs-fullstack   Next.js fullstack (server login, confidential)
  nextjs             Next.js frontend (talks to a separate API, public)
  nestjs             NestJS (confidential server)
  express            Express / Node API (verify-only)
  go                 Go API (verify-only)
  rust               Rust API (verify-only)

Pick the one that matches your codebase. If you have a frontend and a backend in different languages, scaffold both.

What the CLI writes

Every stack produces the same shape: a .env (or platform-specific equivalent), the SDK glue code wired to that env, and a BASE_IDP_SETUP.md with the three remaining manual steps. Here is what comes out for Flutter, for example.

base-idp-flutter/
├── BASE_IDP_SETUP.md
├── lib/
│   └── auth/
│       └── base_idp_auth.dart
└── run.sh
lib/auth/base_idp_auth.dart
import 'package:base_idp/base_idp.dart';

class AppAuth {
  AppAuth()
      : _auth = BaseIdpFlutterAuth(
          config: const BaseIdpConfig(
            clientId: String.fromEnvironment('BASE_IDP_CLIENT_ID'),
          ),
          redirectUri: 'myapp://auth/callback',
        );

  final BaseIdpFlutterAuth _auth;

  Future<BaseIdpMobileSession> signIn() => _auth.login();
  Map<String, dynamic> exchangePayload(BaseIdpMobileSession s) =>
      s.toServerPayload().toJson();
}

For a verify-only Go API the output is even smaller — no env file is required, because a verify-only backend needs nothing in env.

base-idp-go/
├── BASE_IDP_SETUP.md
├── .env       # commented-out placeholder; nothing is required
└── auth/
    └── baseidp.go
auth/baseidp.go
package auth

import (
	"net/http"

	baseidp "github.com/squareexp/base-idp/sdk/go"
)

var client = baseidp.MustNew(baseidp.ConfigFromEnv())

func Protect(next http.Handler) http.Handler {
	return client.RequireAuth(next, baseidp.MiddlewareOptions{})
}

Wiring it into a real project

The generated directory is a reference, not a final layout. Move the file into your app, point your build at it, and follow the three steps in the BASE_IDP_SETUP.md. The steps differ by stack but always come down to:

  1. Install the SDK.
  2. Set the env value you got from the CLI.
  3. Register the redirect URI in the platform that needs it (iOS Info.plist, Android manifest, Next.js route, and so on).

If you scaffolded into ./base-idp-flutter and your app is one level up:

mv base-idp-flutter/lib/auth/base_idp_auth.dart ./lib/auth/
cp base-idp-flutter/run.sh ./run.sh

Then update the redirect URI inside the Dart file and your platform manifests so they all match the one you registered. A mismatch here is the most common reason the browser opens and never returns.

Verifying the integration

Once the SDK is in place, check that your machine can actually reach Base IdP.

npx base-idp test --client-id sq_live_yourapp
Testing Base IdP connection to https://authlayer.squareexp.com...
  healthz: 200 OK
  discovery: 200 OK
  client-config: 200 OK

IdP is reachable.

Three green checks mean the network path is fine, your client id resolves, and your app's registration is active. If any line fails, you have a network or a client-id problem to fix before you debug your code.

What changed in your project

After you finish the setup steps you will have:

  • One SDK in package.json, pubspec.yaml, Cargo.toml, or go.mod.
  • One env value (or none, for a verify-only backend).
  • A login route, a callback route, or a guard — whichever fits your stack.
  • A redirect URI registered both in your code and in your app registration.

Nothing else. There is no Base IdP-specific build step, no init script, no service to run. The SDK does its work at request time.

Where to go next

On this page