Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,12 @@ on:
type: boolean
default: false

sample_b2b_manage:
description: 'b2b/manage'
required: false
type: boolean
default: false

permissions:
contents: write

Expand Down Expand Up @@ -141,6 +147,7 @@ jobs:
sample_better_auth_nextjs: ${{ github.event.inputs.sample_better_auth_nextjs }}
sample_flutter_app_auth: ${{ github.event.inputs.sample_flutter_app_auth }}
sample_self_care_account: ${{ github.event.inputs.sample_self_care_account }}
sample_b2b_manage: ${{ github.event.inputs.sample_b2b_manage }}
run: |
samples='[]'
add() {
Expand All @@ -161,6 +168,7 @@ jobs:
add sample_better_auth_nextjs '{"path":"integrations/better-auth-nextjs","emoji":"🔐","title":"ThunderID Better Auth Next.js Sample"}'
add sample_flutter_app_auth '{"path":"integrations/flutter-app-auth","emoji":"🦋","title":"ThunderID Flutter AppAuth Sample"}'
add sample_self_care_account '{"path":"self-care/account","emoji":"👤","title":"ThunderID Self-Care Account Sample"}'
add sample_b2b_manage '{"path":"b2b/manage","emoji":"🏢","title":"ThunderID B2B Manage Sample"}'
if [ "$samples" = "[]" ]; then
echo "❌ No sample selected. Check at least one sample_* input."
exit 1
Expand Down
42 changes: 40 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,52 @@ on a pull request.

## Adding a sample

- Put it under the area it belongs to and give it a `README.md` that starts with its banner.
Follow the sample-banner skill to render the banner and reference it.
- Put it under the area it belongs to and give it a `README.md` that follows the structure
below. Follow the sample-banner skill to render its banner.
- Depend on the published SDK release, never a workspace or local path.
- Add a row to the table in the root `README.md`.
- Add it to `.github/workflows/release.yml`, in the same pull request, so it can be released.
The workflow has no automatic discovery, so a sample left out of it never gets a release or
a download. Add all three, in the same order as the other samples:
- a `sample_<name>` boolean input under `workflow_dispatch.inputs`, described by its path;
- the matching `sample_<name>: ${{ github.event.inputs.sample_<name> }}` line in the
**Plan Releases** step's `env`;
- an `add sample_<name> '{"path":"<area>/<sample>","emoji":"…","title":"ThunderID … Sample"}'`
line in that step's script.

`workflow_dispatch` allows at most 25 inputs. Count them before adding one.
- Keep its manifest (`package.json`, `pubspec.yaml`, `settings.gradle.kts`, or
`Package.swift`) at the sample root. The pull request builder finds samples by that file
at exactly `<area>/<sample>/`.

## Sample README structure

Every sample README uses the same sections, in this order. Copy an existing README of the same
kind (for example `quickstarts/react/README.md` for a web app, `quickstarts/android/README.md`
for a mobile app) and adapt it rather than starting from scratch.

1. The banner image, then a blank line. See the sample-banner skill.
2. `# <Title>`, matching the banner's alt text, such as `ThunderID React Quickstart` or
`ThunderID Manage Sample`.
3. An intro of one or two paragraphs: what the app does, and the SDK or package it uses, linked.
A short list or table of what it shows can follow.
4. `## Prerequisites`: the runtime and tools with minimum versions, then a running ThunderID
server, with `https://localhost:8090` as the default.
5. `## Get the sample`: the releases link filtered to the sample
(`https://github.com/thunder-id/samples/releases?q=sample%2F<area>%2F<sample>&expanded=true`)
and `npx degit thunder-id/samples/<area>/<sample> my-app`.
6. `## Configure`: creating the application in the Console, named by its Console template
(**React**, **Next.js**, **JavaScript**, and so on), then copying the config template and a
table of every variable it holds.
7. `## Run`: the commands, then the URL to open or what to expect.
8. Optional sections specific to the sample, such as `## How it works`, `## Where things are`,
or a feature walkthrough.
9. `## Learn more`: the docs quickstart guide and the SDK reference on thunderid.dev.
10. `## License`: `Apache License 2.0. See [LICENSE](https://github.com/thunder-id/samples/blob/main/LICENSE).`

Write in plain, direct sentences. Link only to pages that exist; check thunderid.dev links
before adding them.

## Package manager

JavaScript samples use npm, so that a developer who copies one out needs nothing beyond Node.js.
Expand Down
91 changes: 47 additions & 44 deletions b2b/manage/README.md
Original file line number Diff line number Diff line change
@@ -1,75 +1,78 @@
![ThunderID Manage Sample](https://raw.githubusercontent.com/thunder-id/samples/main/.github/assets/banners/b2b-manage.png)

# ThunderID Manage
# ThunderID Manage Sample

ThunderID Manage is a sample app for trying out the ThunderID React SDK on B2B management services. An administrator signs in and manages the resources of a ThunderID server from one place. It is a React (Vite + TypeScript) app built with the [ThunderID React SDK](https://www.npmjs.com/package/@thunderid/react).

## What's included
A React (Vite and TypeScript) app where an administrator signs in and manages the resources of a ThunderID server from one place, built with the [ThunderID React SDK](https://www.npmjs.com/package/@thunderid/react) (`@thunderid/react`). It has two sections:

- **Home**: a short page that explains what the app is for.
- **Agents**: the agent onboarding experience, built with the SDK's React components. You can see the agents on your server, create one through the ThunderID agent onboarding flow, and delete one.

When you create an agent, the app starts the onboarding flow that lives on your ThunderID server. The SDK draws each step the flow sends back: who owns the agent, the agent's details, and the new credentials. The client secret is shown once, hidden behind dots until you choose to show it.
- **Agents**: lists the agents on your server, creates one through the ThunderID agent onboarding flow, and deletes one.

These SDK components are used:
Creating an agent starts the onboarding flow that lives on your ThunderID server. The SDK draws each step the flow sends back: who owns the agent, the agent's details, and the new credentials. The client secret is shown once, hidden until you choose to show it.

| Where | SDK component |
| -------------------------- | ----------------------------------------------------- |
| App setup | `ThunderIDProvider` |
| Top bar and home page | `SignInButton`, `SignedIn`, `SignedOut`, `Loading` |
| Signed-in user | `UserDropdown`, `User` |
| Agents pages | `ProtectedRoute` (from `@thunderid/react-router`) |
| Create agent | `BaseInviteUser`, which runs the flow and draws steps |
| Owner step | The user picker (`BaseUserSelect`) |
| Details and dropdown steps | `TextField`, `Select` |
| Credentials step | `CopyableText`, with the secret hidden until shown |
| Buttons | `Button` |
| Where | SDK component |
| -------------------------- | --------------------------------------------------------- |
| App setup | `ThunderIDProvider` |
| Top bar and home page | `SignInButton`, `SignedIn`, `SignedOut`, `Loading` |
| Signed-in user | `UserDropdown`, `User` |
| Agents pages | `ProtectedRoute` (from `@thunderid/react-router`) |
| Create agent | `BaseInviteUser`, which runs the flow and draws its steps |
| Owner step | The user picker, `BaseUserSelect` |
| Details and dropdown steps | `TextField`, `Select` |
| Credentials step | `CopyableText`, with the secret hidden until shown |
| Buttons | `Button` |

The app also uses the SDK hooks `useThunderID`, `useFetchUsers`, `useFetchAuthFlows`, `useFetchUserTypes`, `useTheme` and `useTranslation`. The organization unit dropdown and the step buttons are drawn by the app itself, through the SDK's custom renderers.
The app also uses the SDK hooks `useThunderID`, `useFetchUsers`, `useFetchAuthFlows`, `useFetchUserTypes`, `useTheme`, and `useTranslation`. The organization unit dropdown and the step buttons are drawn by the app itself, through the SDK's custom renderers.

## Prerequisites

- Node.js 20+ and npm
- ThunderID React SDK 1.4.0 or later (`@thunderid/react`). It is the first release with the user picker (`BaseUserSelect` and `useFetchUsers`) and the masked `CopyableText` that this sample uses. `npm install` fetches it, together with `@thunderid/react-router` 1.3.0.
- A running ThunderID server (defaults to `https://localhost:8090`) and an administrator account
- Node.js 20 or later
- A running ThunderID server (`https://localhost:8090` by default) and an administrator account
- The agent onboarding flow on that server. A standard install already has one, named `default-agent-onboarding-flow`.

New to ThunderID with React? Follow the [React quickstart guide](https://thunderid.dev/docs/next/getting-started/connect-your-application/react/) to set up a ThunderID server and connect a React app to it.
The sample needs `@thunderid/react` 1.4.0 or later, the first release with the user picker (`BaseUserSelect` and `useFetchUsers`) and the masked `CopyableText`. `npm install` fetches it.

## Get the sample

## Setup
Download the latest zip from the [releases](https://github.com/thunder-id/samples/releases?q=sample%2Fb2b%2Fmanage&expanded=true), or copy the source:

1. Start your ThunderID server.
```bash
npx degit thunder-id/samples/b2b/manage my-app
cd my-app
```

2. In the ThunderID Console, [create a React application](https://thunderid.dev/docs/getting-started/connect-your-application/react/#:~:text=2-,Create%20an%20Application,-Sign%20in%20to). Use `http://localhost:5173` as the redirect URL, and copy the client ID it gives you. Then add `http://localhost:5173` to the allowed origins (Settings → CORS), or the browser will block the sign-in requests.
## Configure

3. Configure the app:
1. In the ThunderID Console, create a **React** application with `http://localhost:5173` as its redirect URL, and copy its client ID. Then add `http://localhost:5173` to the allowed origins (**Settings → CORS**), or the browser blocks the sign-in requests.

2. Create your `.env`:

```bash
cp .env.example .env
```

| Variable | Description |
| ----------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| `VITE_THUNDERID_BASE_URL` | Base URL of your ThunderID server. |
| `VITE_THUNDERID_CLIENT_ID` | Client ID of the application (from step 2). |
| `VITE_AGENT_ONBOARDING_FLOW_HANDLE` | Handle of the flow that creates agents. Defaults to `default-agent-onboarding-flow`. |
| `VITE_THUNDERID_RESOURCE` | Optional. The part of ThunderID that guards admin information. A standard install already uses the default. |
| Variable | Description |
| ----------------------------------- | -------------------------------------------------------------------------------------------------- |
| `VITE_THUNDERID_BASE_URL` | Base URL of your ThunderID server. |
| `VITE_THUNDERID_CLIENT_ID` | Client ID of the application. |
| `VITE_AGENT_ONBOARDING_FLOW_HANDLE` | Handle of the flow that creates agents. Defaults to `default-agent-onboarding-flow`. |
| `VITE_THUNDERID_RESOURCE` | Optional. The resource that guards admin information. A standard install already uses the default. |

4. Install and start:
## Run

```bash
npm install
npm run dev
```
```bash
npm install
npm run dev
```

5. Open `http://localhost:5173` and sign in as an administrator.
Open [http://localhost:5173](http://localhost:5173) and sign in as an administrator.

Only administrators can use the Agents section. Anyone else can sign in, but the server turns down the requests and the page shows an error.
Only administrators can use the **Agents** section. Anyone else can sign in, but the server turns down the requests and the page shows an error.

## Docs
## Learn more

- Full SDK reference: [thunderid.dev/docs](https://thunderid.dev/docs)
- [React quickstart guide](https://thunderid.dev/docs/getting-started/connect-your-application/react)
- [React SDK reference](https://thunderid.dev/docs/sdks-and-tools/react/overview)

## License

Apache License 2.0.
Apache License 2.0. See [LICENSE](https://github.com/thunder-id/samples/blob/main/LICENSE).
97 changes: 49 additions & 48 deletions integrations/better-auth-nextjs/README.md
Original file line number Diff line number Diff line change
@@ -1,71 +1,72 @@
![ThunderID Better Auth Sample](https://raw.githubusercontent.com/thunder-id/samples/main/.github/assets/banners/integrations-better-auth-nextjs.png)

# Better Auth + ThunderID Sample
# ThunderID Better Auth Sample

<a href="https://stackblitz.com/fork/github/thunder-id/samples/tree/main/integrations/better-auth-nextjs?file=.env" target="_blank"><img src="https://developer.stackblitz.com/img/open_in_stackblitz.svg" alt="Open in StackBlitz" /></a>
A Next.js 15 App Router app that signs users in to ThunderID through [Better Auth](https://better-auth.com)'s [Generic OAuth plugin](https://better-auth.com/docs/plugins/generic-oauth), configured with the [`@thunderid/better-auth`](https://www.npmjs.com/package/@thunderid/better-auth) provider helper.

A minimal Next.js 15 App Router application demonstrating [Better Auth](https://better-auth.com)'s
[Generic OAuth plugin](https://better-auth.com/docs/plugins/generic-oauth) configured for ThunderID via the
[`@thunderid/better-auth`](https://github.com/thunder-id/javascript-sdks/tree/main/packages/better-auth) provider helper.

All OAuth 2.0 / OIDC handling is performed by Better Auth itself — this sample has no ThunderID SDK
dependency, and keeps users/sessions in an in-memory store (`better-auth/adapters/memory`) that resets on
every server restart. Swap it for a real [database adapter](https://better-auth.com/docs/adapters) in a real
app.
Better Auth does all the OAuth 2.0 and OIDC work; there is no ThunderID SDK in the app. Users and sessions live in an in-memory store (`better-auth/adapters/memory`) that resets when the server restarts. Use a real [database adapter](https://better-auth.com/docs/adapters) in your own app.

## Prerequisites

- Node.js 18+
- A ThunderID application with an OAuth 2.0 / OIDC (`authorization_code`) client
- Node.js 20 or later
- A running ThunderID server (`https://localhost:8090` by default)

## Getting started
## Get the sample

1. Copy the example environment file:
Download the latest zip from the [releases](https://github.com/thunder-id/samples/releases?q=sample%2Fintegrations%2Fbetter-auth-nextjs&expanded=true), or copy the source:

```bash
cp .env.example .env
```
```bash
npx degit thunder-id/samples/integrations/better-auth-nextjs my-app
cd my-app
```

2. Fill in your ThunderID credentials in `.env`:
## Configure

```dotenv
BETTER_AUTH_SECRET=<run: openssl rand -base64 32>
BETTER_AUTH_URL=http://localhost:3000
THUNDERID_ISSUER=https://localhost:8090
THUNDERID_CLIENT_ID=<your-client-id>
THUNDERID_CLIENT_SECRET=<your-client-secret>
```
1. In the ThunderID Console, create an application with an OAuth 2.0 client that uses the `authorization_code` grant and has a client secret. Register this redirect URL on it:

`THUNDERID_CLIENT_ID` and `THUNDERID_CLIENT_SECRET` come from the application's Credentials tab in the
ThunderID console.

3. Register the redirect URI on your ThunderID application (see the app's config notice in this sample for
the exact value to use):

```
```text
http://localhost:3000/api/auth/callback/thunderid
```

4. Install dependencies and start the development server:
Copy its client ID and client secret from the **Credentials** tab.

2. Create your `.env`:

```bash
npm install
npm run dev
cp .env.example .env
```

The app is now running at [http://localhost:3000](http://localhost:3000). Click **Sign in with
ThunderID** to try the flow.
| Variable | Description |
|---|---|
| `BETTER_AUTH_SECRET` | Signs and encrypts Better Auth's session cookies. Generate it with `openssl rand -base64 32`. |
| `BETTER_AUTH_URL` | Base URL the app is served from. The callback URL is derived from it. |
| `THUNDERID_ISSUER` | Your ThunderID server's issuer URL. |
| `THUNDERID_CLIENT_ID` | Client ID of the application. |
| `THUNDERID_CLIENT_SECRET` | Client secret of the application. Server-only. |
| `NODE_TLS_REJECT_UNAUTHORIZED` | Set to `0` in the example to accept a local server's self-signed certificate. Local development only. |

## Run

```bash
npm install
npm run dev
```

Open [http://localhost:3000](http://localhost:3000) and click **Sign in with ThunderID**.

## How it works

- [`lib/auth.ts`](./lib/auth.ts) — the Better Auth server instance. Registers the `genericOAuth` plugin with
the `thunderid()` helper from `@thunderid/better-auth`, which supplies the ThunderID issuer's discovery URL
and default `openid profile email` scopes.
- [`lib/auth-client.ts`](./lib/auth-client.ts) — the Better Auth React client. No client plugin is needed for
ThunderID; sign-in goes through the standard social-provider API.
- [`app/api/auth/[...all]/route.ts`](./app/api/auth/%5B...all%5D/route.ts) — the catch-all route handler that
exposes Better Auth's API via `toNextJsHandler`.
- [`app/page.tsx`](./app/page.tsx) — signs in with `authClient.signIn.social({provider: 'thunderid'})`, shows
the session via `authClient.useSession()`, and signs out with `authClient.signOut()`.
- [`app/components/ConfigNotice.tsx`](./app/components/ConfigNotice.tsx) — shown instead of the app when a
required environment variable is missing, with the exact redirect URI to register on ThunderID.
- [`lib/auth.ts`](./lib/auth.ts) is the Better Auth server instance. It registers the `genericOAuth` plugin with the `thunderid()` helper, which supplies the issuer's discovery URL and the default `openid profile email` scopes.
- [`lib/auth-client.ts`](./lib/auth-client.ts) is the Better Auth React client. ThunderID needs no client plugin; sign-in goes through the standard social provider API.
- [`app/api/auth/[...all]/route.ts`](./app/api/auth/%5B...all%5D/route.ts) is the catch-all route handler that exposes Better Auth's API through `toNextJsHandler`.
- [`app/page.tsx`](./app/page.tsx) signs in with `authClient.signIn.social({provider: 'thunderid'})`, shows the session with `authClient.useSession()`, and signs out with `authClient.signOut()`.
- [`app/components/ConfigNotice.tsx`](./app/components/ConfigNotice.tsx) is shown instead of the app when a required environment variable is missing, with the exact redirect URL to register.

## Learn more

- [Better Auth guide](https://thunderid.dev/sdks-and-tools/better-auth)
- [Better Auth Generic OAuth plugin](https://better-auth.com/docs/plugins/generic-oauth)

## License

Apache License 2.0. See [LICENSE](https://github.com/thunder-id/samples/blob/main/LICENSE).
Loading
Loading