Adds migration instructions

This commit is contained in:
Mihovil Ilakovac 2024-01-11 14:38:39 +01:00
parent c1e180cc78
commit 1eeaf715bc
2 changed files with 319 additions and 0 deletions

View File

@ -0,0 +1,318 @@
---
title: Migration from 0.11.X
---
Wasp made a big change in the way authentication works in version 0.12.0. This guide will help you migrate your app from 0.11.X to 0.12.X.
## What Changed?
### 0.11.X Auth Models
In 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`.
```wasp title="main.wasp"
app myApp {
wasp: {
version: "^0.11.0"
},
title: "My App",
auth: {
userEntity: User,
externalAuthEntity: SocialLogin,
methods: {
gitHub: {}
},
onAuthFailedRedirectTo: "/login"
},
}
entity User {=psl
id Int @id @default(autoincrement())
username String @unique
password String
externalAuthAssociations SocialLogin[]
psl=}
entity SocialLogin {=psl
id Int @id @default(autoincrement())
provider String
providerId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
userId Int
createdAt DateTime @default(now())
@@unique([provider, providerId, userId])
psl=}
```
### New Auth Models
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=}
```
You can read more about the new auth system in the [Auth Entities](/docs/auth/entities) section.
## How to Migrate?
Migrating your existing app to the new auth system is a two-step process:
1. Migrate to the new auth system
1. Cleanup the old auth system
:::caution Migrating a deployed app
To migrate a deployed app, you need to go through the migration steps while deploying the app in between the steps.
Read more about migrating a deployed app in the [Migrating a Deployed App](#migrating-a-deployed-app) section.
:::
### 1. Migrate to the New Auth System
If you have an existing app with authentication set up, you can follow these steps to migrate to the new auth system:
1. Upgrade Wasp to the latest version
1. Bump the version to `^0.12.0` in `main.wasp`
1. Create the new auth tables in the database by running:
```bash
wasp db migrate-dev
```
1. Create a data migration script in `src/server/migrateToNewAuth.ts`
- Below you can find [examples of migration scripts](#example-migration-scripts) for each of the auth methods
1. Add the migration script to the `db.seeds` config:
```wasp title="main.wasp"
app myApp {
wasp: {
version: "^0.12.0"
},
// ...
db: {
seeds: [
import { migrateEmailAuth } from "@server/migrateToNewAuth.js",
import { migrateGoogleAuth } from "@server/migrateToNewAuth.js",
]
},
}
```
1. Run the migration script by running:
```bash
wasp db seed
```
1. Verify still works as expected
1. Migrate to using the new auth helper functions for getting the `email` or `username` of the currently logged in user. Read more about the helpers in the [Auth Entities](/docs/auth/entities#accessing-the-auth-fields) section.
### 2. Cleanup the Old Auth System
Now we need to clean up the old auth system:
1. Delete auth-related fields from `User` entity
1. Remove the `externalAuthEntity` from the `auth` config and the `SocialLogin` entity (if you used it)
1. Run `wasp db migrate-dev` again to remove the redundant fields from the database
1. You can now delete the migration script and the `db.seeds` config
## Migrating a Deployed App
To migrate a deployed app, you need to go through the migration steps while deploying the app in between the steps.
1. Go through the steps of [Migrate to the New Auth System](#1-migrate-to-the-new-auth-system) on your local machine _until the step where you run the migration script_
2. Deploy the app (#1)
3. Run the migration script on the production database
:::info Running the migration script on the production database
If you have an app that is already deployed, you need to run the migration script on the production database.
We wrote instructions on how to do it for **Fly.io** deployments here: https://github.com/wasp-lang/wasp/issues/1464
The instructions should be similar for other deployment providers: setting up a tunnel from your local machine to the production database and running the migration script locally with `DATABASE_URL` set to the production database.
:::
4. Finish the steps of [Migrate to the New Auth System](#1-migrate-to-the-new-auth-system) on your local machine
5. Deploy the app (#2)
6. Go through the steps of [Cleanup the Old Auth System](#2-cleanup-the-old-auth-system) on your local machine
7. Deploy the app (#3)
Your app should now be migrated to the new auth system.
## Example Migration Scripts
### Username & Password
```ts title="src/server/migrateToNewAuth.ts"
import { PrismaClient } from "@prisma/client";
import { ProviderName, UsernameProviderData } from "@wasp/auth/utils";
export async function migrateUsernameAuth(prismaClient: PrismaClient) {
const users = await prismaClient.user.findMany({
include: {
auth: true,
},
});
for (const user of users) {
if (user.auth) {
console.log("User was already migrated, skipping", user);
continue;
}
const providerData: UsernameProviderData = {
hashedPassword: user.password,
};
const providerName: ProviderName = "username";
await prismaClient.auth.create({
data: {
identities: {
create: {
providerName,
providerUserId: user.username.toLowerCase(),
providerData: JSON.stringify(providerData),
},
},
user: {
connect: {
id: user.id,
},
},
},
});
}
}
```
### Email
```ts title="src/server/migrateToNewAuth.ts"
import { PrismaClient } from "@prisma/client";
import { EmailProviderData, ProviderName } from "@wasp/auth/utils";
export async function migrateEmailAuth(prismaClient: PrismaClient) {
const users = await prismaClient.user.findMany({
include: {
auth: true,
},
});
for (const user of users) {
if (user.auth) {
console.log("User was already migrated, skipping", user);
continue;
}
if (!user.email || !user.password) {
console.log("Missing email auth info, skipping user", user);
continue;
}
const providerData: EmailProviderData = {
isEmailVerified: user.isEmailVerified,
emailVerificationSentAt:
user.emailVerificationSentAt?.toISOString() ?? null,
passwordResetSentAt: user.passwordResetSentAt?.toISOString() ?? null,
hashedPassword: user.password,
};
const providerName: ProviderName = "email";
await prismaClient.auth.create({
data: {
identities: {
create: {
providerName,
providerUserId: user.email,
providerData: JSON.stringify(providerData),
},
},
user: {
connect: {
id: user.id,
},
},
},
});
}
}
```
### Google & GitHub
```ts title="src/server/migrateToNewAuth.ts"
import { PrismaClient } from "@prisma/client";
import { ProviderName } from "@wasp/auth/utils";
export async function migrateGoogleAuth(prismaClient: PrismaClient) {
return createSocialLoginMigration(prismaClient, "google");
}
export async function migrateGitHubAuth(prismaClient: PrismaClient) {
return createSocialLoginMigration(prismaClient, "github");
}
async function createSocialLoginMigration(
prismaClient: PrismaClient,
providerName: "google" | "github"
) {
const users = await prismaClient.user.findMany({
include: {
auth: true,
externalAuthAssociations: true,
},
});
for (const user of users) {
if (user.auth) {
console.log("User was already migrated, skipping", user);
continue;
}
const provider = user.externalAuthAssociations.find(
(provider) => provider.provider === providerName
);
if (!provider) {
console.log(`Missing ${providerName} provider, skipping user`, user);
continue;
}
await prismaClient.auth.create({
data: {
identities: {
create: {
providerName,
providerUserId: provider.providerId,
providerData: JSON.stringify({}),
},
},
user: {
connect: {
id: user.id,
},
},
},
});
}
}
```

View File

@ -68,6 +68,7 @@ module.exports = {
],
},
'auth/entities',
'auth/migrate-from-11',
],
},
{