Helpers
user
model
Gadget by default sets the following fields within your user
model:
resetPasswordTokenExpiration
resetPasswordToken
emailVerificationTokenExpiration
emailVerificationToken
password
googleProfileId
googleImageUrl
emailVerified
email
lastName
firstName
lastSignedIn
roles
Google OAuth Sign Up trigger
This trigger executes when a new user signs up using Google OAuth. The entire profile payload from Google is included in the trigger.
Google OAuth Sign In trigger
This trigger executes when an existing user signs in using Google OAuth. The entire profile payload from Google is included in the trigger.
Email Password Sign Up trigger
This trigger executes when a new user signs up using Email-Password authentication. This trigger exposes the signUp
action to your API.
Email Password Sign In trigger
This trigger executes when an existing user signs in using Email-Password authentication. This trigger exposes the signIn
action to your API.
Verify Email trigger
This trigger executes the verifyEmail
action. It finds a user record by emailVerificationToken
and checks emailVerificationTokenExpiration
to see if the token is still valid. If it is the trigger sets emailVerified
to be true.
Send Verify Email trigger
This trigger executes the sendVerifyEmail
action. When the sendVerifyEmail
action is called from your API, this trigger finds a user record by email and checks that emailVerified
is false. It generates a random code and provides it to the action in params.user.emailVerificationCode
. The user record then has emailVerificationToken
set to the SHA256 hash of this code.
Reset Password trigger
This trigger executes the resetPassword
action. It finds a user record by resetPasswordToken
and checks resetPasswordTokenExpiration
to see if the token is still valid. If it is the trigger sets the new password.
Send Reset Password trigger
This trigger executes the sendResetPassword
action. When the sendResetPassword
action is called from your API, this trigger finds a user record by email. It then generates a random code and provides it to the action in params.user.resetPasswordCode
. The user record then has resetPasswordToken
set to the SHA256 hash of this code.
Change Password trigger
This trigger executes the changePassword
action. It checks that the currentPassword
matches the user's current password and then sets the new password.
signUp
action
A user
model's signUp
action is a create action by default.
Its run
function includes setting the lastSignedIn
field of the user record to the current date and time. This indicates when the user last signed in or, in this context, when the user created their account.
In addition, it associates the current user record with the active session.
1import { applyParams, save, ActionOptions } from "gadget-server";23// Powers the form in web/routes/sign-up.tsx45export const run: ActionRun = async ({ params, record, logger, api, session }) => {6 // Applies new 'email' and 'password' to the user record and saves to database7 applyParams(params, record);8 record.lastSignedIn = new Date();9 await save(record);10 if (record.emailVerified) {11 // Assigns the signed-in user to the active session12 session?.set("user", { _link: record.id });13 }14 return {15 result: "ok",16 };17};1819export const onSuccess: ActionOnSuccess = async ({20 params,21 record,22 logger,23 api,24 session,25}) => {26 if (!record.emailVerified) {27 // Sends verification email by calling api/models/users/actions/sendVerifyEmail.ts28 await api.user.sendVerifyEmail({ email: record.email });29 }30};3132export const options: ActionOptions = {33 actionType: "create",34 returnType: true,35 triggers: {36 googleOAuthSignUp: true,37 emailSignUp: true,38 },39};
1import { applyParams, save, ActionOptions } from "gadget-server";23// Powers the form in web/routes/sign-up.tsx45export const run: ActionRun = async ({ params, record, logger, api, session }) => {6 // Applies new 'email' and 'password' to the user record and saves to database7 applyParams(params, record);8 record.lastSignedIn = new Date();9 await save(record);10 if (record.emailVerified) {11 // Assigns the signed-in user to the active session12 session?.set("user", { _link: record.id });13 }14 return {15 result: "ok",16 };17};1819export const onSuccess: ActionOnSuccess = async ({20 params,21 record,22 logger,23 api,24 session,25}) => {26 if (!record.emailVerified) {27 // Sends verification email by calling api/models/users/actions/sendVerifyEmail.ts28 await api.user.sendVerifyEmail({ email: record.email });29 }30};3132export const options: ActionOptions = {33 actionType: "create",34 returnType: true,35 triggers: {36 googleOAuthSignUp: true,37 emailSignUp: true,38 },39};
signIn
action
A user
model's signIn
action is an update action by default.
It updates the lastSignedIn
field of the user
record to the current date and time and associates the current user record with the active session.
1import { applyParams, save, ActionOptions } from "gadget-server";23// Powers form in web/routes/sign-in.tsx45export const run: ActionRun = async ({ params, record, logger, api, session }) => {6 applyParams(params, record);7 record.lastSignedIn = new Date();8 await save(record);9 // Assigns the signed-in user to the active session10 session?.set("user", { _link: record.id });11};1213export const onSuccess: ActionOnSuccess = async ({14 params,15 record,16 logger,17 api,18 session,19}) => {20 // Your logic goes here21};2223export const options: ActionOptions = {24 actionType: "update",25 triggers: {26 googleOAuthSignIn: true,27 emailSignIn: true,28 },29};
1import { applyParams, save, ActionOptions } from "gadget-server";23// Powers form in web/routes/sign-in.tsx45export const run: ActionRun = async ({ params, record, logger, api, session }) => {6 applyParams(params, record);7 record.lastSignedIn = new Date();8 await save(record);9 // Assigns the signed-in user to the active session10 session?.set("user", { _link: record.id });11};1213export const onSuccess: ActionOnSuccess = async ({14 params,15 record,16 logger,17 api,18 session,19}) => {20 // Your logic goes here21};2223export const options: ActionOptions = {24 actionType: "update",25 triggers: {26 googleOAuthSignIn: true,27 emailSignIn: true,28 },29};
signOut
action
A user
model's signOut
action is an update action by default.
It unsets the associated user on the active session, causing the session to be unauthenticated.
1import { ActionOptions } from "gadget-server";23export const run: ActionRun = async ({ params, record, logger, api, session }) => {4 // Removes the user from the active session5 session?.set("user", null);6};78export const onSuccess: ActionOnSuccess = async ({9 params,10 record,11 logger,12 api,13 session,14}) => {15 // Your logic goes here16};1718export const options: ActionOptions = {19 actionType: "update",20 triggers: {21 signOut: true,22 },23};
1import { ActionOptions } from "gadget-server";23export const run: ActionRun = async ({ params, record, logger, api, session }) => {4 // Removes the user from the active session5 session?.set("user", null);6};78export const onSuccess: ActionOnSuccess = async ({9 params,10 record,11 logger,12 api,13 session,14}) => {15 // Your logic goes here16};1718export const options: ActionOptions = {19 actionType: "update",20 triggers: {21 signOut: true,22 },23};
verifyEmail
and sendVerifyEmail
actions
A user
model's verifyEmail
action is a default action file upon app creation, that is designated to handle email verification scenarios for users, as determined by the Gadget developer.
1import { applyParams, save, ActionOptions } from "gadget-server";23// Powers the sign up flow, this action is called from the email generated in /actions/sendVerifyEmail.ts45export const run: ActionRun = async ({ params, record, logger, api }) => {6 // Applies new 'emailVerified' status to the user record and saves to database7 applyParams(params, record);8 await save(record);9 return {10 result: "ok",11 };12};1314export const onSuccess: ActionOnSuccess = async ({15 params,16 record,17 logger,18 api,19}) => {20 // Your logic goes here21};2223export const options: ActionOptions = {24 actionType: "custom",25 returnType: true,26 triggers: {27 verifiedEmail: true,28 },29};
1import { applyParams, save, ActionOptions } from "gadget-server";23// Powers the sign up flow, this action is called from the email generated in /actions/sendVerifyEmail.ts45export const run: ActionRun = async ({ params, record, logger, api }) => {6 // Applies new 'emailVerified' status to the user record and saves to database7 applyParams(params, record);8 await save(record);9 return {10 result: "ok",11 };12};1314export const onSuccess: ActionOnSuccess = async ({15 params,16 record,17 logger,18 api,19}) => {20 // Your logic goes here21};2223export const options: ActionOptions = {24 actionType: "custom",25 returnType: true,26 triggers: {27 verifiedEmail: true,28 },29};
The sendVerifyEmail
action, is a custom action that updates the user
record with the provided parameters and then, if successful, it sends an email to the user containing a reset password link.
1import {2 applyParams,3 save,4 ActionOptions,5 DefaultEmailTemplates,6 Config,7} from "gadget-server";89// Powers the sign up flow, this action is called from api/models/user/actions/signUp.ts1011export const run: ActionRun = async ({ params, record, logger, api, emails }) => {12 // Applies new hashed code 'emailVerificationToken' to the user record and saves to database13 applyParams(params, record);14 await save(record);15 return {16 result: "ok",17 };18};1920export const onSuccess: ActionOnSuccess = async ({21 params,22 record,23 logger,24 api,25 emails,26}) => {27 if (28 !record.emailVerified &&29 record.emailVerificationToken &&30 params.user?.emailVerificationCode31 ) {32 // Generates link to reset password33 const url = new URL("/verify-email", Config.appUrl);34 url.searchParams.append("code", params.user?.emailVerificationCode);35 // Sends link to user36 await emails.sendMail({37 to: record.email,38 subject: `Verify your email with ${Config.appName}`,39 html: DefaultEmailTemplates.renderVerifyEmailTemplate({ url: url.toString() }),40 });41 }42};4344export const options: ActionOptions = {45 actionType: "custom",46 returnType: true,47 triggers: {48 sendVerificationEmail: true,49 },50};
1import {2 applyParams,3 save,4 ActionOptions,5 DefaultEmailTemplates,6 Config,7} from "gadget-server";89// Powers the sign up flow, this action is called from api/models/user/actions/signUp.ts1011export const run: ActionRun = async ({ params, record, logger, api, emails }) => {12 // Applies new hashed code 'emailVerificationToken' to the user record and saves to database13 applyParams(params, record);14 await save(record);15 return {16 result: "ok",17 };18};1920export const onSuccess: ActionOnSuccess = async ({21 params,22 record,23 logger,24 api,25 emails,26}) => {27 if (28 !record.emailVerified &&29 record.emailVerificationToken &&30 params.user?.emailVerificationCode31 ) {32 // Generates link to reset password33 const url = new URL("/verify-email", Config.appUrl);34 url.searchParams.append("code", params.user?.emailVerificationCode);35 // Sends link to user36 await emails.sendMail({37 to: record.email,38 subject: `Verify your email with ${Config.appName}`,39 html: DefaultEmailTemplates.renderVerifyEmailTemplate({ url: url.toString() }),40 });41 }42};4344export const options: ActionOptions = {45 actionType: "custom",46 returnType: true,47 triggers: {48 sendVerificationEmail: true,49 },50};
resetPassword
and sendResetPassword
actions
A user
model's resetPassword
action is a default action file upon app creation, that is designated to handle password reset scenarios for users, as determined by the Gadget developer.
1import { applyParams, save, ActionOptions } from "gadget-server";23// Powers form in web/routes/reset-password.tsx45export const run: ActionRun = async ({6 params,7 record,8 logger,9 api,10 connections,11}) => {12 // Applies new 'password' to the user record and saves to database13 applyParams(params, record);14 await save(record);15 return {16 result: "ok",17 };18};1920export const onSuccess: ActionOnSuccess = async ({21 params,22 record,23 logger,24 api,25 connections,26}) => {27 // Your logic goes here28};2930export const options: ActionOptions = {31 actionType: "custom",32 returnType: true,33 triggers: {34 resetPassword: true,35 },36};
1import { applyParams, save, ActionOptions } from "gadget-server";23// Powers form in web/routes/reset-password.tsx45export const run: ActionRun = async ({6 params,7 record,8 logger,9 api,10 connections,11}) => {12 // Applies new 'password' to the user record and saves to database13 applyParams(params, record);14 await save(record);15 return {16 result: "ok",17 };18};1920export const onSuccess: ActionOnSuccess = async ({21 params,22 record,23 logger,24 api,25 connections,26}) => {27 // Your logic goes here28};2930export const options: ActionOptions = {31 actionType: "custom",32 returnType: true,33 triggers: {34 resetPassword: true,35 },36};
The sendResetPassword
action, is a custom action that updates the user
record with the provided parameters and then, if successful, the action will send a verification email containing a unique link for the user to verify their email.
1import {2 applyParams,3 save,4 ActionOptions,5 DefaultEmailTemplates,6 Config,7} from "gadget-server";89// Powers form in web/routes/forgot-password.tsx1011export const run: ActionRun = async ({ params, record, logger, api, emails }) => {12 // Applies new hashed code 'resetPasswordToken' to the user record and saves to database13 applyParams(params, record);14 await save(record);15 return {16 result: "ok",17 };18};1920export const onSuccess: ActionOnSuccess = async ({21 params,22 record,23 logger,24 api,25 emails,26}) => {27 if (record.resetPasswordToken && params.user?.resetPasswordCode) {28 // Generates link to reset password29 const url = new URL("/reset-password", Config.appUrl);30 url.searchParams.append("code", params.user?.resetPasswordCode);31 // Sends link to user32 await emails.sendMail({33 to: record.email,34 subject: `Reset password request from ${Config.appName}`,35 html: DefaultEmailTemplates.renderResetPasswordTemplate({36 url: url.toString(),37 }),38 });39 }40};4142export const options: ActionOptions = {43 actionType: "custom",44 returnType: true,45 triggers: {46 sendResetPassword: true,47 },48};
1import {2 applyParams,3 save,4 ActionOptions,5 DefaultEmailTemplates,6 Config,7} from "gadget-server";89// Powers form in web/routes/forgot-password.tsx1011export const run: ActionRun = async ({ params, record, logger, api, emails }) => {12 // Applies new hashed code 'resetPasswordToken' to the user record and saves to database13 applyParams(params, record);14 await save(record);15 return {16 result: "ok",17 };18};1920export const onSuccess: ActionOnSuccess = async ({21 params,22 record,23 logger,24 api,25 emails,26}) => {27 if (record.resetPasswordToken && params.user?.resetPasswordCode) {28 // Generates link to reset password29 const url = new URL("/reset-password", Config.appUrl);30 url.searchParams.append("code", params.user?.resetPasswordCode);31 // Sends link to user32 await emails.sendMail({33 to: record.email,34 subject: `Reset password request from ${Config.appName}`,35 html: DefaultEmailTemplates.renderResetPasswordTemplate({36 url: url.toString(),37 }),38 });39 }40};4142export const options: ActionOptions = {43 actionType: "custom",44 returnType: true,45 triggers: {46 sendResetPassword: true,47 },48};
changePassword
action
A user
model's changePassword
action is a default action file upon app creation, that is designated to handle scenarios for users where they have to change/update their password, as determined by the Gadget developer.
1import { applyParams, save, ActionOptions } from "gadget-server";23// Powers form in web/routes/change-password.tsx45export const run: ActionRun = async ({6 params,7 record,8 logger,9 api,10 connections,11}) => {12 // Applies new 'password' to the user record and saves to database13 applyParams(params, record);14 await save(record);15};1617export const onSuccess: ActionOnSuccess = async ({18 params,19 record,20 logger,21 api,22 connections,23}) => {24 // Your logic goes here25};2627export const options: ActionOptions = {28 actionType: "update",29 triggers: {30 changePassword: true,31 },32};
1import { applyParams, save, ActionOptions } from "gadget-server";23// Powers form in web/routes/change-password.tsx45export const run: ActionRun = async ({6 params,7 record,8 logger,9 api,10 connections,11}) => {12 // Applies new 'password' to the user record and saves to database13 applyParams(params, record);14 await save(record);15};1617export const onSuccess: ActionOnSuccess = async ({18 params,19 record,20 logger,21 api,22 connections,23}) => {24 // Your logic goes here25};2627export const options: ActionOptions = {28 actionType: "update",29 triggers: {30 changePassword: true,31 },32};
session
model
All Gadget apps have a session
model that is used to power session management. The current session is always available in Gadget actions and route handlers:
export const run: ActionRun = async ({ params, record, logger, api, session }) => {logger.info({ session }, "the session associated with the current request");};
export const run: ActionRun = async ({ params, record, logger, api, session }) => {logger.info({ session }, "the session associated with the current request");};
csrfToken
All session
records have a special csrfToken
property that can be used to prevent cross-site request forgery (CSRF) attacks.
Gadget automatically checks CSRF tokens for all form submission requests. To submit a form as an authenticated user you must include the CSRF token in the form data.
1import { RouteHandler } from "gadget-server";23const route: RouteHandler = async ({ request, reply, api, logger, connections }) => {4 // send an HTML response with a form that has a CSRF token5 await reply.send(`6 <html>7 <body>8 <form method="POST" action="/submit-form">9 <input type="hidden" name="csrfToken" value="${session.csrfToken}" />10 <button type="submit">Submit</button>11 </form>12 </body>13 </html>14 `);15};1617export default route;
1import { RouteHandler } from "gadget-server";23const route: RouteHandler = async ({ request, reply, api, logger, connections }) => {4 // send an HTML response with a form that has a CSRF token5 await reply.send(`6 <html>7 <body>8 <form method="POST" action="/submit-form">9 <input type="hidden" name="csrfToken" value="${session.csrfToken}" />10 <button type="submit">Submit</button>11 </form>12 </body>13 </html>14 `);15};1617export default route;
Hooks and components
When working with Gadget authentication, there are several hooks and components from our @gadgetinc/react
package that can help you manage the authentication state of your application.
The hooks use the Gadget client's suspense: true
option, making it easier to manage the async nature of the hooks without having to deal with loading state.
Hooks | Description |
---|---|
useSession() | Retrieves the current user session within the app. |
useUser() | If a user is present in the session, it returns the current user; otherwise, it returns null for unauthenticated sessions. |
useAuth() | Returns an object representing the current authentication state of the session. |
useSignOut() | Returns a callback that you can call to sign out your current Gadget User from the current Session . This calls the configured signOutActionApiIdentifier action, which is the User signOut action by default. |
Components | Description |
---|---|
<SignedIn /> | Conditionally renders its children if the current session has a user associated with it, similar to the isSignedIn property of the useAuth() hook. |
<SignedOut /> | Conditionally renders its children if the current session does not have a user associated with it. |
<SignedInOrRedirect /> | Conditionally renders its children based on the user's sign-in status. If a user is currently signed in, it displays its children; otherwise, it redirects the browser using window.location.assign . This functionality is valuable for securing frontend routes. |
<SignedOutOrRedirect /> | Conditionally renders its children when there is no user associated with the current session. However, if the user is signed in, it redirects the browser using window.location.assign . Its purpose is to facilitate redirection of frontend routes based on the user's sign-in status. |