structure in detail, while this page provides a [quick guide](#migrating-your-project-to-the-new-structure) for migrating existing
projects.
### New auth
In Wasp 0.11.X, authentication was based on the `User` model which the developer needed to set up properly and take care of the auth fields like `email` or `password`.
From 0.12.X onwards, authentication is based on the auth models which are automatically set up by Wasp. You don't need to take care of the auth fields anymore.
The `User` model is now just a business logic model and you use it for storing the data that is relevant for your app.
```wasp title="main.wasp"
app myApp {
wasp: {
version: "^0.12.0"
},
title: "My App",
auth: {
userEntity: User,
methods: {
gitHub: {}
},
onAuthFailedRedirectTo: "/login"
},
}
entity User {=psl
id Int @id@default(autoincrement())
psl=}
```
:::caution Regression Note: Multiple Auth Identities per User
With our old auth implementation, if you were using both Google and email auth methods, your users could sign up with Google first and then, later on, reset their password and therefore also enable logging in with their email and password. This was the only way in which a single user could have multiple login methods at the same time (Google and email).
This is not possible anymore. **The new auth system doesn't support multiple login methods per user at the moment**. We do plan to add this soon though, with the introduction of the [account merging feature](https://github.com/wasp-lang/wasp/issues/954).
If you have any users that have both Google and email login credentials at the same time, you will have to pick only one of those for that user to keep when migrating them.
:::caution Regression Note: `_waspCustomValidations` is deprecated
Auth field customization is no longer possible using the `_waspCustomValidations` on the `User` entity. This is a part of auth refactoring that we are doing to make it easier to customize auth. We will be adding more customization options in the future.
These instructions are for migrating your app from Wasp `0.11.X` to Wasp `0.12.X`, meaning they will work for all minor releases that fit this pattern (e.g., the guide applies to `0.12.0`, `0.12.1`, ...).
2.**Position yourself in the terminal** in the directory that is a parent of your wasp project directory (so one level above: if you do `ls`, you should see your wasp project dir listed).
3.**Run the migration script** (replace `foo` at the end with the name of your Wasp project directory) and follow the instructions:
Then, check the changes it did, in case some kind of manual intervention is needed (in which case you should see TODO comments generated by the script).
Alternatively, you can find all the mappings of old imports to the new ones in [this table](https://docs.google.com/spreadsheets/d/1QW-_16KRGTOaKXx9NYUtjk6m2TQ0nUMOA74hBthTH3g/edit#gid=1725669920) and use it to fix some/all of them manually.
Your `package.json` in `foo` should now list these dependencies (Wasp already generated most of the file, you just have to list additional dependencies).
You'll need to wrap all your paths in the `content` field with the `resolveProjectPath` function. This makes sure that the paths are resolved correctly when generating your CSS.
If you didn't customize your Dockerfile or had a custom build process for the Wasp server, you can skip this section.
:::
Between Wasp 0.11.X and 0.12.X, the Dockerfile that Wasp generates for you for deploying the server has changed. If you defined a custom Dockerfile in your project root dir or in any other way relied on its contents, you'll need to update it to incorporate the changes that Wasp 0.12.X made.
We suggest that you temporarily move your custom Dockerfile to a different location, then run `wasp start` to generate the new Dockerfile.
Check out the `.wasp/out/Dockerfile` to see the new Dockerfile and what changes you need to make. You'll probably need to copy some of the changes from the new Dockerfile to your custom one to make your app work with Wasp 0.12.X.
You can follow these steps to migrate to the new auth system (assuming you already migrated the project structure to 0.12, as described [above](#migrating-your-project-to-the-new-structure)):
1.**Migrate `getUserFields` and/or `additionalSignupFields` in the `main.wasp` file to the new `userSignupFields` field.**
If you are not using them, you can skip this step.
In Wasp 0.11.X, you could define a `getUserFieldsFn` to specify extra fields that would get saved to the `User` when using Google or GitHub to sign up.
In 0.12.X, we unified these two concepts into the `userSignupFields` field.
<details>
<summary>Migration for <EmailPill/> and <UsernameAndPasswordPill/></summary>
First, move the value of `auth.signup.additionalFields` to `auth.methods.{method}.userSignupFields` in the `main.wasp` file.
`{method}` depends on the auth method you are using. For example, if you are using the email auth method, you should move the `auth.signup.additionalFields` to `auth.methods.email.userSignupFields`.
To finish, update the JS/TS implementation to use the `defineUserSignupFields` from `wasp/server/auth` instead of `defineAdditionalSignupFields` from `@wasp/auth/index.js`.
<Tabs>
<TabItemvalue="before"label="Before">
```wasp title="main.wasp"
app crudTesting {
// ...
auth: {
userEntity: User,
methods: {
email: {},
},
onAuthFailedRedirectTo: "/login",
// highlight-start
signup: {
additionalFields: import { fields } from "@server/auth/signup.js",
},
// highlight-end
},
}
```
```ts title="src/server/auth/signup.ts"
// highlight-next-line
import { defineAdditionalSignupFields } from '@wasp/auth/index.js'
Read more about the `userSignupFields` function [here](/auth/overview.md#1-defining-extra-fields).
</TabItem>
</Tabs>
</details>
<details>
<summary>Migration for <GithubPill/> and <GooglePill/></summary>
First, move the value of `auth.methods.{method}.getUserFieldsFn` to `auth.methods.{method}.userSignupFields` in the `main.wasp` file.
`{method}` depends on the auth method you are using. For example, if you are using Google auth, you should move the `auth.methods.google.getUserFieldsFn` to `auth.methods.google.userSignupFields`.
To finish, update the JS/TS implementation to use the `defineUserSignupFields` from `wasp/server/auth` and modify the code to return the fields in the format that `defineUserSignupFields` expects.
<Tabs>
<TabItemvalue="before"label="Before">
```wasp title="main.wasp"
app crudTesting {
// ...
auth: {
userEntity: User,
methods: {
google: {
// highlight-next-line
getUserFieldsFn: import { getUserFields } from "@server/auth/google.js"
},
},
onAuthFailedRedirectTo: "/login",
},
}
```
```ts title="src/server/auth/google.ts"
// highlight-next-line
import type { GetUserFieldsFn } from '@wasp/types'
If you want to properly type the `profile` object, we recommend you use a validation library like Zod to define the shape of the `profile` object.
Read more about this and the `defineUserSignupFields` function in the [Auth Overview - Defining Extra Fields](./auth/overview.md#1-defining-extra-fields) section.
1.**Remove the `auth.methods.email.allowUnverifiedLogin` field** from your `main.wasp` file.
In Wasp 0.12.X we removed the `auth.methods.email.allowUnverifiedLogin` field to make our Email auth implementation easier to reason about. If you were using it, you should remove it from your `main.wasp` file.
You should see the new `Auth`, `AuthIdentity` and `Session` tables in your database. You can use the `wasp db studio` command to open the database in a GUI and verify the tables are there. At the moment, they will be empty.
1.**Do the data migration** (move existing users from the old auth system to the new one by filling the new auth tables in the database with their data):
Below we prepared [examples of migration functions](#example-data-migration-functions) for each of the auth methods, for you to use as a starting point.
They should be fine to use as-is, meaning you can just copy them and they are likely to work out of the box for typical use cases, but you can also modify them for your needs.
With each data migration function below, we provided a relevant `api` declaration that you should add to your `main.wasp` file.
1.**Run the data migration function(s)** on the local development database by calling the API endpoints you defined in the previous step.
You can call the endpoint by visiting the URL in your browser, or by using a tool like `curl` or Postman.
For example, if you defined the API endpoint at `/migrate-username-and-password`, you can call it by visiting `http://localhost:3001/migrate-username-and-password` in your browser.
This should be it, you can now run `wasp db studio` again and verify that there is now relevant data in the new auth tables (`Auth` and `AuthIdentity`; `Session` should still be empty for now).
1.**Verify that the basic auth functionality works** by running `wasp start` and successfully signing up / logging in with each of the auth methods.
1.**Update your JS/TS code** to work correctly with the new auth.
You might want to use the new auth helper functions to get the `email` or `username` from a user object. For example, `user.username` might not work anymore for you, since the `username` obtained by the Username & Password auth method isn't stored on the `User` entity anymore (unless you are explicitly storing something into `user.username`, e.g. via `userSignupFields` for a social auth method like Github). Same goes for `email` from Email auth method.
Instead, you can now use `getUsername(user)` to get the username obtained from Username & Password auth method, or `getEmail(user)` to get the email obtained from Email auth method.
Read more about the helpers in the [Auth Entities - Accessing the Auth Fields](auth/entities#accessing-the-auth-fields) section.
After successfully performing migration locally so far, and verifying that your app works as expected, it is time to also migrate our deployed app.
Before migrating your production (deployed) app, we advise you to back up your production database in case something goes wrong. Also, besides testing it in development, it's good to test the migration in a staging environment if you have one.
Between these two steps, so after successfully deploying the new code to production and before migrating the production database data, your app will not be working completely: new users will be able to sign up, but existing users won't be able to log in, and already logged in users will be logged out. Once you do the second step, migrating the production database data, it will all be back to normal. You will likely want to keep the time between the two steps as short as you can.
You can do this by calling the API endpoints you defined in the previous step, just like you did locally. You can call the endpoint by visiting the URL in your browser, or by using a tool like `curl` or Postman.
For example, if you defined the API endpoint at `/migrate-username-and-password`, you can call it by visiting `https://your-server-url.com/migrate-username-and-password` in your browser.
1. In `main.wasp` file, **delete auth-related fields from the `User` entity**, since with 0.12 they got moved to the internal Wasp entity `AuthIdentity`.
- This means any fields that were required by Wasp for authentication, like `email`, `password`, `isEmailVerified`, `emailVerificationSentAt`, `passwordResetSentAt`, `username`, etc.
- There are situations in which you might want to keep some of them, e.g. `email` and/or `username`, if they are still relevant for you due to your custom logic (e.g. you are populating them with `userSignupFields` upon social signup in order to have this info easily available on the `User` entity). Note that they won't be used by Wasp Auth anymore, they are here just for your business logic.
1. In `main.wasp` file, **remove the `externalAuthEntity` field from the `app.auth`** and also **remove the whole `SocialLogin` entity** if you used Google or GitHub auth.
1.**Delete the data migration function(s)** you implemented earlier (e.g. in `src/migrateToNewAuth.ts`) and also the corresponding API endpoints from the `main.wasp` file.
The database migrations will automatically run on successful deployment of the server and delete the now redundant auth-related `User` columns from the database.
The migration functions provided below are written with the typical use cases in mind and you can use them as-is. If your setup requires additional logic, you can use them as a good starting point and modify them to your needs.
Note that all of the functions below are written to be idempotent, meaning that running a function multiple times can't hurt. This allows executing a function again in case only a part of the previous execution succeeded and also means that accidentally running it one time too much won't have any negative effects. **We recommend you keep your data migration functions idempotent**.
res.status(200).json({ message: "Migrated users to the new auth", result });
};
async function migrateUsernameAuth(): Promise<{
numUsersAlreadyMigrated: number;
numUsersNotUsingThisAuthMethod: number;
numUsersMigratedSuccessfully: number;
}> {
const users = await prisma.user.findMany({
include: {
auth: true,
},
});
const result = {
numUsersAlreadyMigrated: 0,
numUsersNotUsingThisAuthMethod: 0,
numUsersMigratedSuccessfully: 0,
};
for (const user of users) {
if (user.auth) {
result.numUsersAlreadyMigrated++;
console.log("Skipping user (already migrated) with id:", user.id);
continue;
}
if (!user.username || !user.password) {
result.numUsersNotUsingThisAuthMethod++;
console.log("Skipping user (not using username auth) with id:", user.id);
continue;
}
const providerData: UsernameProviderData = {
hashedPassword: user.password,
};
const providerName: ProviderName = "username";
await prisma.auth.create({
data: {
identities: {
create: {
providerName,
providerUserId: user.username.toLowerCase(),
providerData: JSON.stringify(providerData),
},
},
user: {
connect: {
id: user.id,
},
},
},
});
result.numUsersMigratedSuccessfully++;
}
return result;
}
```
</details>
2. Provide a way for users to migrate their password
There is a **breaking change between the old and the new auth in the way the password is hashed**. This means that users will need to migrate their password after the migration, as the old password will no longer work.
Since the only way users using username and password as a login method can verify their identity is by providing both their username and password (there is no email or any other info, unless you asked for it and stored it explicitly), we need to provide them a way to **exchange their old password for a new password**. One way to handle this is to inform them about the need to migrate their password (on the login page) and provide a custom page to migrate the password.
There is a **breaking change between the old and the new auth in the way the password is hashed**. This means that users will need to reset their password after the migration, as the old password will no longer work.