Orkestia
Blog
SDKs

Auth SDK — Sign in with Orkestia

Browser PKCE / OAuth SDK for your app's end-users — hosted login, RS256 JWTs, silent renew, no client secret

@orkestia/auth is the browser SDK for "Sign in with Orkestia" — the OAuth 2.0 / OIDC authorization-code flow with PKCE that authenticates your app's users, not your org members.

To provision an identity app and wire this SDK, paste the agent prompt on App Enablement into an MCP-connected agent.

Your frontend never sees a password and never holds a client secret. The public client_key is safe to ship in the browser. After login you hold an RS256 JWT you can send to the workflow API as Authorization: Bearer ….

Early access (v0.0.x). The API may change before 1.0. npm i @orkestia/auth will work once the package is published; until then install from the repository.

Install

npm i github:orkestia/orkestia-auth-sdk

1. Provision the app (once)

An org member (or an agent over MCP) provisions the identity app. One workflow returns the client_key and every URL the SDK needs:

identity.app.provision({
  name: "My App",
  redirect_uris: [
    "http://localhost:5173/callback",
    "https://myapp.com/callback",
  ],
})
// → { client_key, client_uuid, redirect_uris,
//     integration: { issuer, discovery_url, authorize_url, token_url, jwks_url, flow, sdk } }

Registered redirect_uris are accepted immediately — there is no manual CORS step. Add more later with identity.app.configure-client. See App Enablement and Sign in with Orkestia.

2. Wire the browser

import { createOrkestiaAuth } from "@orkestia/auth"

const auth = createOrkestiaAuth({ clientKey: "orkestia_…" })

// On your "Sign in" button:
await auth.signIn()

// On the registered redirect_uri page:
const session = await auth.handleCallback()
// { token, claims, email, endUserUuid } | null

// Anywhere later:
const current = auth.getSession()
auth.signOut()

signIn() builds the PKCE challenge and redirects to login.orkestia.dev. After the user authenticates, Orkestia returns to your redirect_uri with a one-time ?code. handleCallback() exchanges the code for the JWT. The token never appears in a URL.

API

MethodPurpose
signIn()Start PKCE — redirect to the hosted login
handleCallback()Exchange ?code for a session (OrkestiaSession | null)
getSession()Current stored session (claims decoded; expiry checked)
renew()Silent refresh (prompt=none); throws OrkestiaLoginRequiredError if the session is gone
signOut()Clear the local session
verify(token)Verify the RS256 signature against the published JWKS
register(email, password)Create an end-user account (does not consume a seat)
createOrkestiaAuth({
  clientKey: "orkestia_…",                          // required
  loginUrl: "https://login.orkestia.dev",           // default
  identityApi: "https://workflow-api.orkestia.dev", // default
  redirectUri: location.origin + "/",               // must be registered
  storage: sessionStorage,                          // default
  autoRenew: true,                                  // default
  renewSkewSeconds: 60,
  onRequiresLogin: (err) => auth.signIn(),
})

Silent renew

Access tokens are short-lived. With autoRenew on (the default) the SDK refreshes renewSkewSeconds before expiry using a hidden OIDC prompt=none iframe. The hosted login's session cookie is the long-lived state.

import { createOrkestiaAuth, OrkestiaLoginRequiredError } from "@orkestia/auth"

try {
  const session = await auth.renew()
} catch (err) {
  if (err instanceof OrkestiaLoginRequiredError) {
    await auth.signIn() // session revoked or expired — full re-login
  }
}

If the session was revoked (identity.end-user.session.revoke) or expired, renew() clears local state, fires onRequiresLogin, throws, and does not retry.

Use the JWT with the workflow SDKs

The session token is a normal Bearer. Pass it to the Node or Python workflow SDK, or to REST. The engine injects the end-user principal immutably — the caller cannot set or override it.

import { LtIntegWorkflowsClient } from "@ltinteg/workflows-sdk"

const session = auth.getSession()
const client = new LtIntegWorkflowsClient({
  baseUrl: "https://workflow-api.orkestia.dev",
  token: session.token,
})

// Only workflows you exposed, and only this user's rows.
const run = await client.start("virtual.<composition_uuid>@1", {
  /* free inputs only */
})

Next: End-user data and App Data.

The OAuth contract

The SDK implements this loop. You can do it by hand if you do not want the package; the URLs also arrive in the provision integration bundle.

StepEndpoint
AuthorizeGET https://login.orkestia.dev/authorize?client_key&redirect_uri&state&code_challenge&code_challenge_method=S256
TokenPOST https://workflow-api.orkestia.dev/api/auth/end-user/token { code, code_verifier } → { token }
JWKSGET https://workflow-api.orkestia.dev/api/auth/end-user/jwks (RS256, iss=login.orkestia.dev)
Register / verify-email / reset / MFAunder https://workflow-api.orkestia.dev/api/auth/end-user/*

Org members vs end-users

Do not use this SDK for your team operating Orkestia. Members sign in through org login (Cognito). @orkestia/auth is only for end-users of an app you built.

Org members

Your team — dashboard, API tokens, workflow SDKs, MCP.

End-users

Your users — this SDK, seat-gated, only exposed workflows.