loginId
used here. If you supplied a username or email address loginId
, the message will be sent via email. If you supplied a phone number loginId
then the message will be delivered via an SMS messenger.
} />
${theme.message('forgot-password-email-sent', email)}
[@helpers.link url="/oauth2/authorize"]${theme.message('return-to-login')}[/@helpers.link]
[/@helpers.main] ``` ```html title="After" [@helpers.main title=theme.message('forgot-password-message-sent-title')]${theme.message('forgot-password-message-sent', loginId)}
[@helpers.link url="/oauth2/authorize"]${theme.message('return-to-login')}[/@helpers.link]
[/@helpers.main] ``` ### OAuth complete registration template You may need users to have passwords, but passwords are optional. Consider the following example: * A user has already logged in * The user does not have a password * The user performs self-serve registration for an application that uses basic registration In this case, FusionAuth takes the user to the `OAuth complete registration` page to add any required fields for the application. If the user does not have a password you can collect it on this page. To support this, FusionAuth provides a new template variable named `passwordSet`, which indicates whether or not the user has a password. Use this variable to show a password field if you require the user to have a password. Note that for a new or logged-out user that registers for this application, the password will generally be collected on the initial registration page. Logged-in users bypass the initial page. For example, before: ```html title="Before" [#if application.registrationConfiguration.mobilePhone.enabled] [@helpers.input type="text" name="user.mobilePhone" id="mobilePhone" placeholder=theme.message("mobilePhone") leftAddon="phone" required=application.registrationConfiguration.mobilePhone.required/] [/#if] [#if application.registrationConfiguration.preferredLanguages.enabled] [@helpers.locale_select field="" name="user.preferredLanguages" id="preferredLanguages" label=theme.message("preferredLanguage") required=application.registrationConfiguration.preferredLanguages.required /] [/#if] ``` ```html title="After" [#if application.registrationConfiguration.mobilePhone.enabled] [@helpers.input type="text" name="user.mobilePhone" id="mobilePhone" placeholder=theme.message("mobilePhone") leftAddon="phone" required=application.registrationConfiguration.mobilePhone.required/] [/#if] [#if !(passwordSet!false)] [@helpers.input type="password" name="user.password" id="password" autocomplete="new-password" placeholder=theme.message('password') leftAddon="lock" required=true/] [#if application.registrationConfiguration.confirmPassword] [@helpers.input type="password" name="confirm.user.password" id="passwordConfirm" autocomplete="new-password" placeholder=theme.message('passwordConfirm') leftAddon="lock" required=true/] [/#if] [/#if] [#if application.registrationConfiguration.preferredLanguages.enabled] [@helpers.locale_select field="" name="user.preferredLanguages" id="preferredLanguages" label=theme.message("preferredLanguage") required=application.registrationConfiguration.preferredLanguages.required /] [/#if] ``` ### OAuth passwordless template To support passwordless logins with phone numbers, several changes must be made to allow submission of one-time or short codes on the passwordless page. The changes include: new hidden form fields, an `if` surrounding the `loginId` field with a new `oneTimeCode` field, and a change to the button text based on whether the form is being submitted or a code is being sent. ```html title="Before" ``` ```html title="After" ``` ### OAuth register template To support phone numbers in basic registration, a `user.phoneNumber` field must be added. ```html title="Before" [#if application.registrationConfiguration.loginIdType == 'email'] [@helpers.input type="text" name="user.email" id="email" autocomplete="username" autocapitalize="none" autocorrect="off" spellcheck="false" autofocus=true placeholder=theme.message('email') leftAddon="user" required=true/] [#else] [@helpers.input type="text" name="user.username" id="username" autocomplete="username" autocapitalize="none" autocorrect="off" spellcheck="false" autofocus=true placeholder=theme.message('username') leftAddon="user" required=true/] [/#if] ``` ```html title="After" [#if application.registrationConfiguration.loginIdType == 'email'] [@helpers.input type="text" name="user.email" id="email" autocomplete="username" autocapitalize="none" autocorrect="off" spellcheck="false" autofocus=true placeholder=theme.message('email') leftAddon="user" required=true/] [#elseif application.registrationConfiguration.loginIdType == 'phoneNumber'] [@helpers.input type="text" name="user.phoneNumber" id="phoneNumber" autocomplete="mobile" autocapitalize="none" autocorrect="off" spellcheck="false" autofocus=true placeholder=theme.message('phoneNumber') leftAddon="mobile" required=true/] [#else] [@helpers.input type="text" name="user.username" id="username" autocomplete="username" autocapitalize="none" autocorrect="off" spellcheck="false" autofocus=true placeholder=theme.message('username') leftAddon="user" required=true/] [/#if] ``` ## Version 1.53.3 Version `1.53.3` includes a change to persist the value of the `Keep me signed in` checkbox from the hosted login pages through an external identity provider workflow. This checkbox value indicates whether the user wishes to create an SSO session after login. If the Google IdP's `loginMethod` is configured as `UsePopup` or `UseVendorJavaScript`, existing custom advanced themes require an update to incorporate the fix for the Google IdP. You can update the template via the API using `theme.templates.helpers` or by modifying the *Helpers* template in the admin UI. Google IdPs configured with a `loginMethod` value of `UseRedirect` do not require this update, but you may consider making the change preemptively in case the `loginMethod` is changed later. To allow the `Keep me signed in` value to be persisted through a Google IdP login in an existing custom advanced theme, remove the `data-login_uri` attribute and its value from the `div` with Id `g_id_onload` in the `googleButton` macro and add the `data-callback` attribute in its place. Replace ```html{eventType}
.
{eventType}
.
{eventType}
.
{eventType}
.
{eventType}
.
{eventType}
.
{eventType}
.
{eventType}
.
{eventType}
.
{eventType}
.
{eventType}
.
{eventType}
.
{eventType}
.
{eventType}
.
{eventType}
.
This event is generated when a refresh token is revoked. The JSON includes either the User Id and User or the Application Id depending on what was revoked. It will also include the time to live duration (in seconds) for each Application. This value is used to determine if JWTs are valid or not based on their expiration instants.
The following scenarios will cause this event to be generated:
This example JSON would reflect a scenario where a single refresh token is revoked for a single user for a single application.
A map of Application Id to the configured time to live (TTL) for the access token (JWT). This can be used to identify the maximum amount of time after this event occurred where an un-expired access token may be held by a user.
If you take the
This map will contain a single entry for the application represented by the
{eventType}
.
This example JSON would reflect a scenario where all refresh tokens owned by a single user are revoked.
A map of Application Id to the configured time to live (TTL) for the access token (JWT). This can be used to identify the maximum amount of time after this event occurred where an un-expired access token may be held by a user.
If you take the
This map will contain a single entry for the application represented by the
{eventType}
.
This example JSON would reflect a scenario where all refresh tokens issued for a specific application are revoked.
A map of Application Id to the configured time to live (TTL) for the access token (JWT). This can be used to identify the maximum amount of time after this event occurred where an un-expired access token may be held by a user.
If you take the
This map will contain a single entry for the application represented by the
{eventType}
.
{eventType}
.
{eventType}
.
This event is generated when a User Action is taken on a user and when temporal actions transition between phases.
A temporal action is one that has a start time and a duration. When a phase transition occurs for a temporal action, an event will be sent to the webhook. See the
{eventType}
.
{eventType}
.
{eventType}
.
{eventType}
.
{eventType}
.
{eventType}
.
{eventType}
.
{eventType}
.
{eventType}
.
{eventType}
.
{eventType}
.{/* eslint-disable-line */}
{eventType}
.{/* eslint-disable-line */}
{eventType}
.{/* eslint-disable-line */}
{eventType}
.{/* eslint-disable-line */}
{eventType}
.
{eventType}
.
{eventType}
.
{eventType}
.
{eventType}
.
{eventType}
.
{eventType}
.
This event is generated when a user registration is created.
The final state of the operation which caused the webhook is not persisted to FusionAuth until after the webhook finishes; [learn more](/docs/extend/events-and-webhooks/writing-a-webhook#calling-fusionauth-apis-in-webhooks).
{eventType}
.
{eventType}
.
{eventType}
.
{eventType}
.
{eventType}
.
{eventType}
.
{eventType}
.
{eventType}
.
{eventType}
.
This event is generated when a user is updated. The event will include the before and after versions of the User being updated.
This event is currently generated each time a user logs in via an IdP, such as Google, or OIDC -- even if the user data or user details in the IdP have not been modified.
{eventType}
.
This is a protected application.
``` Then, start a python web server. ```shell title="Start the web server" python3 -m http.server ``` You should be able to visit `http://localhost:8080` and see something like this.