Try It Out
Each walkthrough on this page runs one of the agent identity patterns from Identity for AI Agents against a working sample.
Meet Wayfinder
Wayfinder is a travel-booking application with an AI agent built in — the Wayfinder Concierge, an in-app chat assistant. Through Wayfinder, consumers search for flights and hotels, book trips, and ask the Concierge to do the same on their behalf.
Wayfinder has two principals you'll meet in these walkthroughs: consumers who book travel and chat with the agent, and the Wayfinder Concierge that acts as their assistant. Each carries its own identity in ThunderID.
Meet the Cast
- Consumers book travel and chat with the agent.
- John Doe is the customer with full access. He can book through the UI and talk to the Wayfinder Concierge. He carries both the
Booking UserandChat Userroles. - Jane Smith also books through the UI, but does not have access to the Wayfinder Concierge. She carries only the
Booking Userrole.
- John Doe is the customer with full access. He can book through the UI and talk to the Wayfinder Concierge. He carries both the
- The Wayfinder Concierge is a first-class principal in ThunderID with its own credentials. It uses its own identity for browsing tools, and switches to a user-context token when a tool needs the consumer's consent.
Sample Architecture
Wayfinder runs as three deployable pieces. The Wayfinder Web browser app hosts the chat widget, the AI Agent drives the conversation, and the Wayfinder Server exposes booking data over MCP.
ThunderID sits alongside as the identity authority. It issues a user token on sign-in, an M2M token for the agent itself, and an on-behalf-of (OBO) token when the agent acts for the consumer. The Wayfinder Server also fetches ThunderID's JWKS to validate every incoming JWT.
Identity Model
The setup below creates a set of ThunderID resources. Here is what each one is and how it maps to Wayfinder concepts.
Organization
ThunderID can host many isolated tenants. Wayfinder needs only one, so everything lives in a single organization.
User Types
A user type defines who can exist in the system and what attributes they carry. Each user record belongs to exactly one user type. Wayfinder defines a Customer user type for the two demo consumers — John Doe and Jane Smith — with standard attributes like username, email, and name.
See User Types.
Resources and Permissions
The AI Agent API and the Wayfinder Server both need protection in the sample. The AI Agent API decides who is allowed to chat with the agent at all, and the Wayfinder Server decides who can book travel. Each is registered as a resource server, with its actions generating one permission per action.
A resource server groups the APIs of one backend. Each resource server defines one or more resources, each resource defines actions, and ThunderID automatically generates a permission of the form <resource>:<action> for every action.
wayfinder-agent (Resource Server)
└── agent (Resource)
└── access → agent:access (Permission)
booking-api (Resource Server)
└── booking (Resource)
├── read → booking:read (Permission)
├── create → booking:create
├── cancel → booking:cancel
└── recommend → booking:recommend
Permissions are issued to the access tokens. See Resource Servers.
Roles
A role bundles permissions for a class of principal. A user's or agent's effective permissions are the union of permissions across their roles. Wayfinder defines three roles:
Chat User: grantsagent:access, the permission required to talk to the Wayfinder Concierge.Booking User: grantsbooking:read,booking:create, andbooking:cancelfor booking travel through the UI.Recommender: grantsbooking:recommend, the permission the Wayfinder Concierge needs to surface flight recommendations on its own.
John Doe carries both user roles; Jane Smith carries only Booking User. The Recommender role is assigned to the WAYFINDER-CONCIERGE agent, not to a user.
See Authorization.
Application
An application is the OAuth2 client that ThunderID issues tokens to. Wayfinder Web is registered as WAYFINDER — a public, PKCE-enforced browser client.
See Manage Applications.
Agent
An agent is a first-class non-human principal in ThunderID with its own credentials. The Wayfinder Concierge is registered as WAYFINDER-CONCIERGE, with two grants enabled:
client_credentials— for the agent's own M2M token, used to call browsing tools.authorization_code(with PKCE) — for the on-behalf-of flow, where the user consents and the agent calls mutating tools as the user.
See Manage Agents and Agent Authentication.
Flows
A flow is the sequence of steps a user moves through when signing in or granting consent. Wayfinder Web uses the bundled default-basic-flow for sign-in. The agent uses a separate Wayfinder Agent Authentication Flow that drives the OBO consent screen.
See Build a Flow.
Setup
Complete the setup once. Every walkthrough below builds on the same starting point.
The two tabs below offer the same end state through different paths.
- Quick Start imports a single bundle that creates every resource the walkthroughs share — including the agent.
- Configure It Yourself creates the same resources manually so you can see how each one is made.
Before you begin, make sure you have:
-
ThunderID running locally, with
http://localhost:5173added tocors.allowed_originsinbackend/cmd/server/repository/conf/deployment.yamlso the web app can call ThunderID from the browser. Keep existing entries and restart ThunderID after the change. See Get ThunderID.cors:
allowed_origins:
- "http://localhost:5173" -
The Wayfinder sample distribution. The Get ThunderID step above already pulls the archive that ships it. It contains a
thunderid-config/directory with an importable YAML config and athunderid.envfile, plus the Wayfinder web frontend and the Concierge services. -
Node.js 20+ for running the sample's services.
-
An LLM API key. One of an Anthropic API key from console.anthropic.com or a Google Gemini API key from aistudio.google.com.
- Quick Start
- Configure It Yourself
Import the Wayfinder configuration bundle.
-
Edit
thunderid-config/thunderid.envif you want to change the agent's client secret. The default value (wayfinder-agent-secret) matches the sample's defaults. -
Import the bundle into ThunderID.
- Sign in to the ThunderID Console at https://localhost:8090/console.
- On first sign-in, a welcome screen appears with an Open button. (Later, reach the same screen from the user profile menu in the top-right corner of the Console.)
- Click Open and select your
thunderid-config/thunderid-config.yamlfile from the sample distribution. - Select your
thunderid-config/thunderid.envfile to provide the environment variables referenced in the YAML. - The Console imports the files and reports the resources it created when the import completes.
The import creates:
- Resource servers:
wayfinder-agent(withagent:access) andbooking-api(withbooking:read,booking:create,booking:cancel,booking:recommend). - Roles:
Chat User,Booking User, andRecommender, with users and the agent pre-assigned:Chat User→john.doe.Booking User→john.doeandjane.smith.Recommender→WAYFINDER-CONCIERGE.
- Application:
WAYFINDER(public, PKCE, redirect tohttp://localhost:5173). - Agent:
WAYFINDER-CONCIERGE(confidential client withclient_credentials+authorization_codegrants). - Flow:
Wayfinder Agent Authentication Flow(assigned to the agent). - Users:
john.doe/john.doeandjane.smith/jane.smith(typed asCustomer).
-
Start the sample following the commands in its README.
Create every resource manually in the ThunderID console.
-
Create the
wayfinder-agentresource server.Invoke the Resource Management API to create the resource server. Set the identifier to
wayfinder-agent. Replace<organization-unit-id>with the ID of your default organization unit (look it up viaGET /organization-units):curl -kL -X POST https://localhost:8090/resource-servers \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <access-token>' \
-d '{
"name": "Wayfinder Agent",
"description": "Controls access to the Wayfinder Concierge agent",
"identifier": "wayfinder-agent",
"ouId": "<organization-unit-id>",
"delimiter": ":"
}'Add a resource with handle
agentunder it:curl -kL -X POST https://localhost:8090/resource-servers/<wayfinder-agent-rs-id>/resources \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <access-token>' \
-d '{ "name": "Agent", "handle": "agent" }'Then add one action under the resource:
curl -kL -X POST https://localhost:8090/resource-servers/<wayfinder-agent-rs-id>/resources/<agent-resource-id>/actions \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <access-token>' \
-d '{ "name": "Access", "handle": "access" }'Action Generated permission accessagent:accessSee Resource Servers.
-
Create the
booking-apiresource server.Invoke the Resource Management API again. Set the identifier to
booking-api:curl -kL -X POST https://localhost:8090/resource-servers \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <access-token>' \
-d '{
"name": "Booking API",
"description": "Controls booking operations in the Wayfinder Travel API",
"identifier": "booking-api",
"ouId": "<organization-unit-id>",
"delimiter": ":"
}'Add a resource with handle
booking:curl -kL -X POST https://localhost:8090/resource-servers/<booking-api-rs-id>/resources \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <access-token>' \
-d '{ "name": "Booking", "handle": "booking" }'Then add four actions under the resource — repeat the call below for each handle (
read,create,cancel,recommend):curl -kL -X POST https://localhost:8090/resource-servers/<booking-api-rs-id>/resources/<booking-resource-id>/actions \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <access-token>' \
-d '{ "name": "Read", "handle": "read" }'Action Generated permission readbooking:readcreatebooking:createcancelbooking:cancelrecommendbooking:recommend -
Create the
Chat Userrole.Send a
POSTto/roles. The role grantsagent:accesson thewayfinder-agentresource server:curl -kL -X POST https://localhost:8090/roles \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <access-token>' \
-d '{
"name": "Chat User",
"description": "Grants access to use the Wayfinder Concierge agent",
"ouId": "<organization-unit-id>",
"permissions": [
{
"resourceServerId": "<wayfinder-agent-rs-id>",
"permissions": ["agent:access"]
}
]
}' -
Create the
Booking Userrole.Grant it
booking:read,booking:create, andbooking:cancelonbooking-api:curl -kL -X POST https://localhost:8090/roles \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <access-token>' \
-d '{
"name": "Booking User",
"description": "Grants booking permissions for the Wayfinder sample",
"ouId": "<organization-unit-id>",
"permissions": [
{
"resourceServerId": "<booking-api-rs-id>",
"permissions": ["booking:read", "booking:create", "booking:cancel"]
}
]
}' -
Create the
Recommenderrole.Grant it
booking:recommendonbooking-api. This role will be assigned to the Wayfinder Concierge, not to a user:curl -kL -X POST https://localhost:8090/roles \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <access-token>' \
-d '{
"name": "Recommender",
"description": "Grants the booking:recommend permission to the Wayfinder Concierge",
"ouId": "<organization-unit-id>",
"permissions": [
{
"resourceServerId": "<booking-api-rs-id>",
"permissions": ["booking:recommend"]
}
]
}'See Authorization.
-
Create the
Customeruser type.Navigate to User Types → Add User Type. Name it
Customerand define the schema with the attributes the agent needs to issue claims for:Attribute Type Required Notes usernamestring Yes Unique passwordstring No Marked as a credential emailstring Yes Unique given_namestring No family_namestring No See User Types.
-
Create the two demo users.
Navigate to Users → Add User. Select the
Customeruser type and create:Username Password john.doejohn.doejane.smithjane.smithSee Manage Users.
-
Assign user roles.
- Roles → Chat User → Assignments tab → Add Assignment. Pick User and assign
john.doe. - Roles → Booking User → Assignments tab → Add Assignment. Pick User and assign both
john.doeandjane.smith.
- Roles → Chat User → Assignments tab → Add Assignment. Pick User and assign
-
Register the
WAYFINDERapplication.Navigate to Applications → Add Application and choose Browser App as the type. Configure:
Setting Value Client ID WAYFINDERRedirect URI http://localhost:5173Allowed grants authorization_code,refresh_tokenPKCE Required Allowed user types CustomerSee Manage Applications.
-
Register the
WAYFINDER-CONCIERGEagent.
Navigate to Agents → Add Agent. Name the agent WAYFINDER-CONCIERGE, then:
- Capture the client secret. ThunderID prints it only once. You will use it in
ai-agent/.env. - Under Protocol settings, enable the Authorization Code grant. Client Credentials is on by default for agents.
- Add the redirect URI
http://localhost:5173/agent-callback. - Under
accessToken.userAttributes, addgiven_name,family_name,email,groups.
See Manage Agents and Agent Authentication.
-
Assign the
Recommenderrole to the agent.With the agent created, complete the role assignment:
- Roles → Recommender → Assignments tab → Add Assignment. Pick Agent and assign
WAYFINDER-CONCIERGE.
- Roles → Recommender → Assignments tab → Add Assignment. Pick Agent and assign
-
Create the
Wayfinder Agent Authentication Flow.Navigate to Flows and create a flow that authenticates the user with username and password, then shows a consent screen listing the
booking:*permissions the agent is requesting. Attach the flow to theWAYFINDER-CONCIERGEagent.See Build a Flow.
-
Start the sample following the commands in its README, passing the agent client secret you captured in step 10.
Walkthrough Structure
Each walkthrough below starts from the setup above. The walkthroughs map onto the patterns from Identity for AI Agents, so you can read about a pattern and then run it.
Select a walkthrough to begin: