---
title: Signing up on Subako Cloud
description: Creating an organization from a browser, through the Service API.
sidebar:
  order: 5
---

Subako Cloud has a second API beside the one `SubakoClient` reaches. The Service API creates organizations: someone signs in at Subako Cloud's identity provider, and the ID token that sign-in ends in creates an organization with them invited as its admin. An on-premises deployment runs no Service API, so none of this applies there.

`SubakoServiceClient` reaches it. The sign-in is the OAuth 2.0 authorization code grant with PKCE, relayed by the Service API, so the page that starts it never holds a client secret:

```ts
import { createCodeChallenge, SubakoServiceClient } from "@subako-ai/sdk";

const service = new SubakoServiceClient();
const redirectUri = "https://console.example.com/signup/callback";

// 1. Before the browser leaves: keep the verifier and a fresh state, then go.
const { verifier, challenge } = await createCodeChallenge();
const state = crypto.randomUUID();
sessionStorage.setItem("signup", JSON.stringify({ verifier, state }));
const { authorization_url } = await service.auth.authorize({
	redirect_uri: redirectUri,
	state,
	code_challenge: challenge,
});
location.assign(authorization_url);
```

The identity provider sends the browser back to `redirect_uri` with `code` and `state`. Check the state is the one you sent, then redeem the code with the verifier:

```ts
// 2. On the callback page.
const params = new URLSearchParams(location.search);
const kept = JSON.parse(sessionStorage.getItem("signup") ?? "{}");
if (params.get("state") !== kept.state) throw new Error("the sign-in came back for another request");

const { id_token, email } = await service.auth.exchangeCode({
	code: params.get("code") ?? "",
	code_verifier: kept.verifier,
	redirect_uri: redirectUri,
});

// 3. Create the organization as the person who signed in.
const signedUp = new SubakoServiceClient({ idToken: id_token });
const organization = await signedUp.organizations.create({ handle: "acme", name: "Acme Corp" });
// organization.invited_email === email: they sign in to it as that account.
```

A deployment takes its sign-ups through one redirect URI, its console's callback, and refuses any other with an `InvalidRequestError`. A deployment that takes no sign-up from a browser answers `ForbiddenError`. A repeated `create` with the same ID token answers with the organization as it stands rather than a second one.

`SubakoServiceClient` defaults to `https://service.us.cloud.subako.ai`. It takes the same `baseUrl`, `fetch`, `headers`, `timeout` and `maxRetries` as the other clients, and retries the same way. Without an `idToken` it sends no `Authorization` header, which is what the sign-in calls need and what a proxy attaching its own credential expects.
