Wasp supports e-mail authentication out of the box, along with email verification and "forgot your password?" flows. It provides a set of routes and email templates that you can use to implement it in your app.
In this guide, we'll go through the easiest way to set up email authentication: using Wasp's [Auth UI](/docs/guides/auth-ui) components. Check out the Auth UI guide for more details on how to customize the UI.
We'll need to take the following steps to set up email authentication:
- [ ] Set up email authentication in `main.wasp`
- [ ] Add the user entity
- [ ] Add the routes and pages
- [ ] Set up the email sender in `main.wasp` and `.env.server`
- [ ] Use Auth UI components in our pages
Outline of the Wasp file we'll be working with:
```c title="main.wasp"
// Configuring e-mail authentication
app myApp { ... }
// Defining User entity
entity User { ... }
// Defining routes and pages
route SignupRoute { ... }
page SignupPage { ... }
// ...
```
### Email authentication in `main.wasp`
Let's first set up the email authentication by adding the following to our `main.wasp` file:
```c title="main.wasp"
app myApp {
wasp: {
version: "^0.10.0"
},
title: "My App",
auth: {
// 1. Specify the user entity
userEntity: User,
methods: {
// 2. Enable email authentication
email: {
// 3. Specify the email from field
fromField: {
name: "My App Postman",
email: "hello@itsme.com"
},
// 4. Specify the email verification and password reset options
emailVerification: {
clientRoute: EmailVerificationRoute,
getEmailContentFn: import { getVerificationEmailContent } from "@server/auth/email.js",
allowUnverifiedLogin: false,
},
passwordReset: {
clientRoute: PasswordResetRoute,
getEmailContentFn: import { getPasswordResetEmailContent } from "@server/auth/email.js",
},
},
},
onAuthFailedRedirectTo: "/login",
onAuthSucceededRedirectTo: "/profile"
},
}
```
### User entity
Then we'll define the `User` entity in our `main.wasp` file:
```c title="main.wasp" {4-8}
// 5. Define the user entity
entity User {=psl
id Int @id@default(autoincrement())
email String? @unique
password String?
isEmailVerified Boolean @default(false)
emailVerificationSentAt DateTime?
passwordResetSentAt DateTime?
// Add your own fields below
// ...
psl=}
```
### Routes and pages
Next, we need to define the routes and pages for the authentication pages. We'll show the React code later, but for now we'll just define the routes and pages.
We'll add the following to our `main.wasp` file:
```c title="main.wasp"
// 6. Define the routes
route SignupRoute { path: "/signup", to: SignupPage }
page SignupPage {
component: import { Signup } from "@client/pages/auth/Signup.tsx"
}
route LoginRoute { path: "/login", to: LoginPage }
page LoginPage {
component: import { Login } from "@client/pages/auth/Login.tsx"
}
route RequestPasswordResetRoute { path: "/request-password-reset", to: RequestPasswordResetPage }
page RequestPasswordResetPage {
component: import { RequestPasswordReset } from "@client/pages/auth/RequestPasswordReset.tsx",
}
route PasswordResetRoute { path: "/password-reset", to: PasswordResetPage }
page PasswordResetPage {
component: import { PasswordReset } from "@client/pages/auth/PasswordReset.tsx",
}
route EmailVerificationRoute { path: "/email-verification", to: EmailVerificationPage }
page EmailVerificationPage {
component: import { EmailVerification } from "@client/pages/auth/EmailVerification.tsx",
}
```
### Email sender
We'll use SendGrid in this guide to send our e-mails. You can use any of the supported email providers. Read more about setting up the email sender in the [email sender setup guide](/docs/guides/sending-emails).
To set up SendGrid to send emails, we will add the following to our `main.wasp` file:
```c title="main.wasp"
app myApp {
...
emailSender: {
provider: SendGrid,
}
}
```
... and add the following to our `.env.server` file:
```c title=".env.server"
SENDGRID_API_KEY=<yourkey>
```
## Using Auth UI
:::info
We are using [Tailwind CSS](https://tailwindcss.com/) to style the page. Read more about how to add it [here](/docs/integrations/css-frameworks#tailwind).
:::
### Signup page
![Auth UI](/img/authui/signup.png)
We are using the `SignupForm` component from `@wasp/auth/forms/Signup` to render the signup form.
```tsx title="client/pages/auth/Signup.tsx"
import { Link } from 'react-router-dom'
import { SignupForm } from '@wasp/auth/forms/Signup'
By default, Wasp requires the e-mail to be verified before allowing the user to log in. This is done by sending a verification email to the user's email address and requiring the user to click on a link in the email to verify their email address.
Our setup looks like this:
```c title="main.wasp"
emailVerification: {
clientRoute: EmailVerificationRoute,
getEmailContentFn: import { getVerificationEmailContent } from "@server/auth/email.js",
allowUnverifiedLogin: false,
}
```
When the user receives an e-mail, they receive a link that goes to the client route specified in the `clientRoute` field. In our case, this is the `EmailVerificationRoute` route we defined in the `main.wasp` file.
```c title="main.wasp"
route EmailVerificationRoute { path: "/email-verification", to: EmailVerificationPage }
page EmailVerificationPage {
component: import { EmailVerification } from "@client/pages/auth/EmailVerification.tsx",
}
```
### Email verification page
![Auth UI](/img/authui/email_verification.png)
This route goes to the `EmailVerification` page, which is defined in the `EmailVerification.tsx` file:
If everything is okay, <Linkto="/login">go to login</Link>
</span>
</div>
</div>
</div>
</div>
)
}
```
You'll notice we are using the `VerifyEmailForm` component from the `@wasp/auth/forms/VerifyEmail` module. This will give a nice-looking form for the user to verify their e-mail.
We will also override the default e-mail content. We are using the `getVerificationEmailContent` function from the `@server/auth/email.js` file to generate the email content.
```ts title="server/auth/email.ts"
import { GetVerificationEmailContentFn } from '@wasp/types'
We will also override the default e-mail content that's sent. We are using the `getVerificationEmailContent` function from the `@server/auth/email.js` file to generate the email content.
```ts title="server/auth/email.ts"
import { GetPasswordResetEmailContentFn } from '@wasp/types'
When the user receives an e-mail, they receive a link that goes to the client route specified in the `clientRoute` field. In our case, this is the `PasswordResetRoute` route we defined in the `main.wasp` file.
```c title="main.wasp"
route PasswordResetRoute { path: "/password-reset", to: PasswordResetPage }
page PasswordResetPage {
component: import { PasswordReset } from "@client/pages/auth/PasswordReset.tsx",
}
```
This route goes to the `PasswordResetPage` page, which is defined in the `PasswordReset.tsx` file. Users can enter their new password here:
If everything is okay, <Linkto="/login">go to login</Link>
</span>
</div>
</div>
</div>
</div>
)
}
```
### Logout action
To implement the logout action, you can use the `logout` function from the `@wasp/auth/logout` module. We can add it for example, to the `Navbar` component:
```jsx title="client/components/Navbar.tsx"
import logout from '@wasp/auth/logout';
export function Navbar() {
return (
<div>
<buttononClick={logout}>Logout</button>
</div>
)
}
```
### Getting the user in our client & server code
You read about our `useAuth` hook in [this section](/docs/language/features#accessing-the-currently-logged-in-user) of the docs.
In short, you can use the `useAuth` hook in your client code to get the currently logged-in user. If there is no user logged in, it will return `null`.
```jsx title="client/pages/Profile.tsx"
import useAuth from '@wasp/auth'
export function Profile() {
const { data: user } = useAuth()
if (!user) {
return <div>You are not logged in!</div>
}
return (
<div>
Hello, {user.email}!
</div>
)
}
```
## Conclusion
And that's it! We now have a full authentication system in our app. We can register new users, login, logout, verify their e-mail, and reset their password.
We hope you enjoyed this guide and that you learned something new. If you have any questions, feel free to ask them on [our Discord server](https://discord.gg/rzdnErX).