Openstatus www.openstatus.dev

๐Ÿ“ Clerk migration blog (#813)

* ๐Ÿ“ first draft

* ๐Ÿ“ blog post

* chore: blog post

* chore: blog post

* chore: remove unused code snippet

* ๐Ÿ”ฅ small improvments

* ๐Ÿ”ฅ small improvments

---------

Co-authored-by: mxkaske <maximilian@kaske.org>

authored by

Thibault Le Ouay
mxkaske
and committed by
GitHub
d6c5c4c9 a7d9ab0d

+142
apps/web/public/assets/posts/migration-auth-clerk-to-next-auth/title.png

This is a binary file and will not be displayed.

+142
apps/web/src/content/posts/migration-auth-clerk-to-next-auth.mdx
··· 1 + --- 2 + title: Why we migrated from Clerk to NextAuth (Auth.js). 3 + description: 4 + Discover the reasons behind our decision to migrate from Clerk to NextAuth. 5 + author: 6 + name: Thibault Le Ouay Ducasse 7 + url: https://twitter.com/thibaultleouay 8 + publishedAt: 2024-05-15 9 + image: /assets/posts/migration-auth-clerk-to-next-auth/title.png 10 + --- 11 + 12 + We recently switched from [Clerk](https://clerk.com) to NextAuth 13 + ([Auth.js](https://authjs.dev)) for our authentication. Now, let's explore the 14 + reasons for this decision. 15 + 16 + ## Why did we migrate from Clerk to NextAuth (Auth.js)? ๐Ÿค” 17 + 18 + First, Clerk is an amazing product. But we are building an open-source project 19 + and creating an account on Clerk, setting up social login, and routing the 20 + webhook to localhost was a pain for new contributors as it required a tunnel to 21 + `localhost:3000` via e.g. [ngrok](https://ngrok.com). 22 + 23 + Our goal is to improve the contributor experience (CX) for OpenStatus by 24 + speeding up the time to first line of code. _#TTFLOC_ 25 + 26 + Our efforts have already simplified the process significantly. With SQLite and 27 + now NextAuth, we can seed the DB and login with an email (magic link gets 28 + printed in the console) within less than a minute. 29 + 30 + <Tweet id="1790147744964780230" /> 31 + 32 + > Not gonna lie, we still have some more improvements to make, like adding a 33 + > better Tinybird setup, but saving it for later! โœ๏ธ 34 + 35 + ## Why did we start with Clerk? ๐Ÿง‘โ€๐Ÿ’ป 36 + 37 + When we started OpenStatus, we needed a way to authenticate users. We wanted to 38 + make it easy for users to sign up for our platform. Clerk was a good choice for 39 + us because it provided a simple way to authenticate users. 40 + 41 + The documentation is clear, the setup is straightforward, and it is working 42 + flawlessly with Next.js App Router. 43 + 44 + At the same time, NextAuth was starting a transition to Auth.js and while we 45 + wanted to use the latest tech and have chosen 46 + [drizzle](https://orm.drizzle.team) over [prisma](https://www.prisma.io), there 47 + was no proper adapter for it. 48 + 49 + Back then, Clerk was the perfect fit. 50 + 51 + ## Why did we pick NextAuth (Auth.js) and not Lucia? ๐Ÿ”‘ 52 + 53 + First, when we thought about migrating from Clerk, we considered 54 + [Lucia](https://lucia-auth.com/). Lucia is an amazing authentication library 55 + that is gaining popularity built by [Pilcrow](https://pilcrowonpaper.com/). 56 + 57 + We were scared about the stability and direction of the project. When you 58 + implement authentication, you want to do it once and forget about it after. 59 + 60 + <Tweet id="1785701672012107841" /> 61 + 62 + We decided to go with NextAuth because it was more mature, and it seemed more 63 + stable to us. Additionally, we both had some experience with NextAuth. It was a 64 + good choice for us as we did not have to learn a new library. 65 + 66 + ## How did we migrate from Clerk to NextAuth (Auth.js)? ๐Ÿš€ 67 + 68 + We were scared of the migration at first. We thought it would be long and hard. 69 + But the migration was quite simple, as we were already storing most of the user 70 + data in our database. 71 + 72 + ### What we already had in place 73 + 74 + Whenever a user signed up with Clerk, we stored the `user`'s data in our 75 + database. We had to store the `tenantId` from Clerk to be able to fetch map the 76 + user, and we additionally stored `email`, `name`, `photoUrl`, and SQLite created 77 + an additional primary key `id`. 78 + 79 + All the other information of the user's social account (Google, GitHub OAuth) 80 + was stored in Clerk. 81 + 82 + ### Starting with NextAuth 83 + 84 + Whenever you start with NextAuth, you choose your DB/ORM adapter and create the 85 + tables you need: 86 + 87 + - `users` 88 + - `sessions` 89 + - `accounts` 90 + - `verificationTokens` 91 + 92 + With drizzle as our ORM, we followed the following steps from 93 + [here](https://authjs.dev/getting-started/adapters/drizzle), including using 94 + SQLite as schema. 95 + 96 + Now because we already had the `users` table, we extended it with the necessary 97 + fields or mappings in our 98 + [extended adapter](https://github.com/openstatusHQ/openstatus/blob/main/apps/web/src/lib/auth/adapter.ts) 99 + (e.g., we have kept the `photoUrl` field and did not use the `image` field from 100 + NextAuth to store the social image of the user). NextAuth allows you to override 101 + the adapter functions and that's what we did: we overrode the `getUser` and 102 + `createUser` functions to match our current user db schema. 103 + 104 + The other tables `sessions`, `accounts`, and `verificationTokens` were created 105 + as is. 106 + 107 + Now you might wonder: **How did we migrate the data?** We simply did not. 108 + 109 + While Clerk has all the information for the social `accounts` of every user, we 110 + are connecting the user to the account when they log in the next time with. 111 + NextAuth provides a 112 + [`allowDangerousEmailAccountLinking`](https://authjs.dev/reference/core/providers#allowdangerousemailaccountlinking) 113 + property that re-links the `user` to the `account` when they log in with the 114 + same email. 115 + 116 + > We still have some issue with types and NextAuth. We have an open issue 117 + > [#812](https://github.com/openstatusHQ/openstatus/issues/812) if you want to 118 + > help us ๐Ÿค—. 119 + 120 + ### Customizing the UI 121 + 122 + We have been using Clerk's UI for a long time and swapped it with custom 123 + components. But luckily our website is powered by 124 + [shadcn UI](https://ui.shadcn.com) and we could easily create the components. 125 + 126 + ## Conclusion 127 + 128 + If you are building an open-source project, we recommend NextAuth. But if it's a 129 + closed-source SaaS project, Clerk is a good choice. 130 + 131 + We are happy with our decision to migrate from Clerk to NextAuth (Auth.js). 132 + While we will miss some Clerk features (analytics), we look forward to exploring 133 + what NextAuth offers us. 134 + 135 + If you have any questions about our migration, feel free to send us an email at 136 + [ping@openstatus.dev](mailto:ping@openstatus.dev). 137 + 138 + Our main PR for the migration is 139 + [#801](https://github.com/openstatusHQ/openstatus/pull/801) while we implemented 140 + the magic link for dev mode in 141 + [#806](https://github.com/openstatusHQ/openstatus/pull/806) and improved the 142 + types in [#807](https://github.com/openstatusHQ/openstatus/pull/807).