Self Sign-Up
This walkthrough configures ThunderID so that new consumers can register themselves with an email and password. ThunderID creates a user record and returns the new user to your app signed in.
Enable Self Sign-Up covers the requirements story behind this use case.
Complete the Login walkthrough first. The user type, application, and sign-in flow set up there are required here.
Pick Your Pattern
Redirect-based
In the redirect-based pattern, your app redirects the user to ThunderID for the entire registration experience. After the user fills in the sign-up form, ThunderID creates the account and returns them to your app signed in.
Configure ThunderID
1. Build a registration flow
Build a REGISTRATION flow using the Flow Designer or the flows API. See Build a Flow.
Your registration flow should collect the user's credentials, provision the account, and return an auth assertion so the user lands signed in.
To automatically assign a default role to every self-registered user, create the role under Roles → Add Role. Then set properties.assignRole to that role's ID on the ProvisioningExecutor node in your flow. See Authorization.
Sample registration flow
{
"handle": "consumer-registration-flow",
"name": "Consumer Registration Flow",
"flowType": "REGISTRATION",
"nodes": [
{ "id": "start", "type": "START", "onSuccess": "user_type_resolver" },
{
"id": "user_type_resolver",
"type": "TASK_EXECUTION",
"executor": { "name": "UserTypeResolver" },
"onSuccess": "prompt_credentials",
"onIncomplete": "prompt_usertype"
},
{
"id": "prompt_usertype",
"type": "PROMPT",
"meta": {
"components": [
{ "align": "center", "type": "TEXT", "id": "heading_usertype", "label": "Choose your account type", "variant": "HEADING_1" },
{
"type": "BLOCK",
"id": "block_usertype",
"components": [
{ "type": "SELECT", "id": "usertype_input", "ref": "userType", "label": "Account type", "placeholder": "Select an account type", "required": true, "options": [] },
{ "type": "ACTION", "id": "action_usertype", "label": "Continue", "variant": "PRIMARY", "eventType": "SUBMIT" }
]
}
]
},
"prompts": [
{
"inputs": [ { "ref": "usertype_input", "identifier": "userType", "type": "SELECT", "required": true } ],
"action": { "ref": "action_usertype", "nextNode": "user_type_resolver" }
}
]
},
{
"id": "prompt_credentials",
"type": "PROMPT",
"meta": {
"components": [
{ "align": "center", "type": "TEXT", "id": "heading_credentials", "label": "Create your account", "variant": "HEADING_1" },
{
"type": "BLOCK",
"id": "block_credentials",
"components": [
{ "type": "TEXT_INPUT", "id": "input_username", "ref": "username", "label": "Username", "placeholder": "Pick a username", "required": true },
{ "type": "PASSWORD_INPUT", "id": "input_password", "ref": "password", "label": "Password", "placeholder": "Choose a password", "required": true },
{ "type": "ACTION", "id": "action_credentials", "label": "Continue", "variant": "PRIMARY", "eventType": "SUBMIT" }
]
}
]
},
"prompts": [
{
"inputs": [
{ "ref": "input_username", "identifier": "username", "type": "TEXT_INPUT", "required": true },
{ "ref": "input_password", "identifier": "password", "type": "PASSWORD_INPUT", "required": true }
],
"action": { "ref": "action_credentials", "nextNode": "basic_auth" }
}
]
},
{
"id": "basic_auth",
"type": "TASK_EXECUTION",
"executor": { "name": "BasicAuthExecutor" },
"onSuccess": "provisioning"
},
{
"id": "provisioning",
"type": "TASK_EXECUTION",
"executor": {
"name": "ProvisioningExecutor",
"inputs": [
{ "ref": "input_username", "identifier": "username", "type": "TEXT_INPUT", "required": true },
{ "ref": "input_password", "identifier": "password", "type": "PASSWORD_INPUT", "required": true }
]
},
"onSuccess": "auth_assert",
"onIncomplete": "prompt_schema_attrs"
},
{
"id": "prompt_schema_attrs",
"type": "PROMPT",
"meta": {
"components": [
{ "align": "center", "type": "TEXT", "id": "heading_schema_attrs", "label": "Tell us about you", "variant": "HEADING_1" },
{
"type": "BLOCK",
"id": "block_dynamic_user_inputs",
"components": [
{ "type": "DYNAMIC_INPUT_PLACEHOLDER", "id": "dynamic_inputs" },
{ "type": "ACTION", "id": "action_schema_attrs", "label": "Continue", "variant": "PRIMARY", "eventType": "SUBMIT" }
]
}
]
},
"prompts": [
{ "inputs": [], "action": { "ref": "action_schema_attrs", "nextNode": "provisioning" } }
]
},
{
"id": "auth_assert",
"type": "TASK_EXECUTION",
"executor": { "name": "AuthAssertExecutor" },
"onSuccess": "end"
},
{ "id": "end", "type": "END" }
]
}
2. Attach the registration flow to your application
Go to Applications → your app → Flows tab. Under Registration Flow, select the flow you created. Save the application.
See Manage Applications.
Integrate into Your App
Trigger sign-up from your app using the SDK. The registration experience is hosted by ThunderID, so your app only needs a sign-up entry point:
| Framework | Where to integrate |
|---|---|
| React | React Quickstart — <SignUpButton /> component |
| Next.js | Next.js Quickstart |
| Vue | Vue Quickstart |
| Browser SDK | Browser SDK Overview |
The redirect-based pattern is standard OAuth 2.0 authorization code flow with PKCE, so any OIDC-compliant SDK works — you are not limited to the ThunderID SDK. Point it at your ThunderID server's discovery endpoint (http://localhost:8080/oauth2/token/.well-known/openid-configuration) and use your Client ID from the registered application.
Try It Out
- Start your app and open it in the browser.
- Click your sign-up button. The browser navigates to ThunderID.
- Fill in a username, email, and password for a new user.
- Submit. ThunderID runs the registration flow, creates the user, and redirects back to your app.
- Verify that the new user lands in your app signed in.
App-native step-by-step
Coming soon. See the App-native pattern for what to expect.
App-native managed
Coming soon. See the App-native pattern for what to expect.
Direct API
Coming soon. See the Direct API pattern for what to expect.
Going Deeper
- Want to understand how user types and schemas work? See User Types in Identity Concepts.
- Want to automatically assign a role to self-registered users? See Roles in Identity Concepts.
- Want to see this use case running against the Wayfinder sample? See Self Sign-Up — Try It Out.