DEV Community

Cover image for How to Manage User Authentication in React.js, Next.js, Vue.js, and Nuxt.js Using Clerk
Hugo Ramon Pereira
Hugo Ramon Pereira

Posted on

How to Manage User Authentication in React.js, Next.js, Vue.js, and Nuxt.js Using Clerk

INTRODUCTION

Authentication is a very important component to any software, application, system, it provides an extra layer of security by restricting areas of your application. For example a dashboard with important information, it can not be accessed unless the user is authenticated. Of course we can implement user, email and password for the user to create and then the user receives an email to validate the email and only then the user can access the content which is allowed for the ones authenticated, this flow is still very popular in use, but it has additional steps that many users are somewhat bored to take, since authentication with a provider be it Google, Microsoft, Apple or others is much simpler, with just a few clicks you can get authenticated and you don't even have to leave the current screen you are in. This ease of access should definitely be considered when building your applications so that the user can choose which one he wants.

In this article we will use Clerk with React.js and Next.js, unfortunately Clerk is not fully supported for Vue.js or Nuxt.js applications yet, in the Clerk's official docs we can find mentions for Vue.js but to use it via SDK.

CLERK WITH REACT.JS

The first step is to log into Clerk's website and choose the providers you want to be available in your application. You can choose up to 3 providers in the free-tier, if you wish to have more providers then you will need to upgrade your account.

Image description

The second step to add it to a React.js application is quite simple. First we need to install the clerk package:

npm install @clerk/clerk-react
Enter fullscreen mode Exit fullscreen mode

Then we need to set up our environment variables, first check if you already have a env.local file to add the key there, in case you don't have this file you can go ahead and create it to add the clerk publishable key, as follows:

VITE_CLERK_PUBLISHABLE_KEY=pk_test_************************
Enter fullscreen mode Exit fullscreen mode

The next step is to import the publishable key, we can do this by going to the main.ts file and import it there, you can also add a if check to avoid Typescript errors.

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
import './index.css'

// Import your publishable key
const PUBLISHABLE_KEY = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY

if (!PUBLISHABLE_KEY) {
  throw new Error('Missing Publishable Key')
}

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
)

Enter fullscreen mode Exit fullscreen mode

Now we have to add the to our application also in the main.ts file but now we have to wrap the whole app with the as shown below and attach the publishableKey to it:

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
import './index.css'
import { ClerkProvider } from '@clerk/clerk-react'

// Import your publishable key
const PUBLISHABLE_KEY = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY

if (!PUBLISHABLE_KEY) {
  throw new Error('Missing Publishable Key')
}

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <ClerkProvider publishableKey={PUBLISHABLE_KEY} afterSignOutUrl="/">
      <App />
    </ClerkProvider>
  </React.StrictMode>,
)

Enter fullscreen mode Exit fullscreen mode

Now the final step is to add the Clerk Components in the header component to handle the authentication steps such as sign in, sign out, the button with the Authenticators we choose during the process like Google, Microsoft, Github, Apple and many others available. You can organize your Header component the way you want just import the components from Clerk and it should work.

import { SignedIn, SignedOut, SignInButton, UserButton } from '@clerk/clerk-react'

export function Header() {
  return (
    <header>
      <SignedOut>
        <SignInButton />
      </SignedOut>
      <SignedIn>
        <UserButton />
      </SignedIn>
    </header>
  )
}
Enter fullscreen mode Exit fullscreen mode

And don't forget to add the package React-Router-Dom to navigate to whatever the page is after the user is authenticated.

CLERK WITH NEXT.JS

To add Clerk to a Next.js application the steps are almost identical, just a few changes, let's see how to do that.

First log into Clerk's website with your account and select the providers and proceed to add the publishable key and remember that Next.js has a different naming convention for its environment variables.

And using Next.js requires 2 values to be added in the environment file, a secret key is added in Next.js a publishable key and a secret key:

NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_************************
CLERK_SECRET_KEY=sk_test_************************
Enter fullscreen mode Exit fullscreen mode

Next step is to add a middleware to intercept routes for unauthenticated users, you can create a file named middleware.ts in the root directory. Then this is the code to make it validate routes and force authentication by using the functions auth() and protect() provided by Clerk:

import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server'

const isProtectedRoute = createRouteMatcher(['/dashboard(.*)', '/forum(.*)'])

export default clerkMiddleware((auth, req) => {
  if (isProtectedRoute(req)) auth().protect()
})

export const config = {
  matcher: [
    // Skip Next.js internals and all static files, unless found in search params
    '/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',
    // Always run for API routes
    '/(api|trpc)(.*)',
  ],
}
Enter fullscreen mode Exit fullscreen mode

And now we are going to add to our main layout.tsx file wrapping the entire application and make Clerk globally available.

import { ClerkProvider, SignInButton, SignedIn, SignedOut, UserButton } from '@clerk/nextjs'
import './globals.css'
import Header from '@/components/Header';


export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <ClerkProvider>
      <html lang="en">
        <body>
          <Header />
          <main>{children}</main>
        </body>
      </html>
    </ClerkProvider>
  )
}
Enter fullscreen mode Exit fullscreen mode

And now we add our Header component and use Clerk components:

import { SignedIn, SignedOut, SignInButton, UserButton } from '@clerk/nextjs';

export function Header() {
  return (
    <header>
      <SignedOut>
        <SignInButton />
      </SignedOut>
      <SignedIn>
        <UserButton />
      </SignedIn>
    </header>
  )
}
Enter fullscreen mode Exit fullscreen mode

CLERK WITH VUE

In order to add Clerk to a Vue.js application we are gonna need to use the Clerk's SDK. And the process is very simple, this is one of the benefits of using Clerk, its simplicity.

Install the SDK into your project by using the command:

npm install vue-clerk
Enter fullscreen mode Exit fullscreen mode

Add the publishable key to your project, unlike Next.js, for Vue.js and React.js there is only one key to be added to the .env.local file:

VITE_CLERK_PUBLISHABLE_KEY=pk_test_************************
Enter fullscreen mode Exit fullscreen mode

Then import the Clerk publishable key in the main.ts file into the src folder:

import { createApp } from 'vue'
import App from './App.vue'

const PUBLISHABLE_KEY = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY

if (!PUBLISHABLE_KEY) {
  throw new Error('Missing Publishable Key')
}

const app = createApp(App)
app.mount('#app')
Enter fullscreen mode Exit fullscreen mode

Add clerkPlugin from vue-clerk

import { createApp } from 'vue'
import App from './App.vue'
import { clerkPlugin } from 'vue-clerk'

const PUBLISHABLE_KEY = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY

if (!PUBLISHABLE_KEY) {
  throw new Error('Missing Publishable Key')
}

const app = createApp(App)
app.use(clerkPlugin, {
  publishableKey: PUBLISHABLE_KEY
})
app.mount('#app')
Enter fullscreen mode Exit fullscreen mode

Now create your header component and make use of the Clerk pre-built components:

<script setup>
     import { SignedIn, SignedOut, SignInButton, UserButton } from 'vue-clerk'
</script>

<template>
  <SignedOut>
    <SignInButton />
  </SignedOut>
  <SignedIn>
    <UserButton />
  </SignedIn>
</template>
Enter fullscreen mode Exit fullscreen mode

And use vue-router to navigate to the authenticated pages when the user is done authenticating.

CLERK WITH NUXT.JS

Nuxt.js applications require the use of Vue-clerk to and some additional steps in order to make Clerk work with Nuxt.js architecture. It's a different process just like with Next.js because both technologies have similar purposes.

In the nuxt.config.ts we add the module vue-clerk/nuxt into the modules array and by doing so all the components and composables will be auto-imported

// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['vue-clerk/nuxt'],
  clerk: {
    appearance: {},
  }
})
Enter fullscreen mode Exit fullscreen mode

And now the environment variables are added in your environment file:

NUXT_PUBLIC_CLERK_PUBLISHABLE_KEY=your_publishable_key
NUXT_CLERK_SECRET_KEY=your_secret_key
Enter fullscreen mode Exit fullscreen mode

The environment variables will be loaded in the nuxt.config.ts file using the runtimeConfig and beware the naming conventions they must match the NUXT_PUBLIC_YOUR_ENV and the runtimeConfig object otherwise we might run into inconsistencies between the dev and build environment.

export default defineNuxtConfig({
  modules: ['vue-clerk/nuxt'],
  clerk: {
    appearance: {},
  }
  runtimeConfig: {
    public: {
      clerkPublishableKey: process.env.CLERK_PUBLISHABLE_KEY,
    },
  }
});
Enter fullscreen mode Exit fullscreen mode

Now the next step is to use Clerk Components in for example a Header component and use it.

<script lang="ts" setup>
// You don't have to import anything from  Clerk
</script>

<template>
  <div>
    <SignIn />
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode

We also have to protect the routes that need authentication and if the user is not authorized he will be redirected to a home page or wherever we want.

// middleware/auth.ts
import { defineNuxtRouteMiddleware, navigateTo } from '#app';
import { useClerk } from '@clerk/clerk-vue';

export default defineNuxtRouteMiddleware(() => {
  const clerk = useClerk();

  if (!clerk.user.value) {
    return navigateTo('/sign-in');
  }
});
Enter fullscreen mode Exit fullscreen mode

Next step is to add types to make sure Clerk works with Typescript. Since we are using SDKs for Vue.js and Nuxt.js it is not necessary to install the package @clerk/types because the SDKs include their own type definitions. You can read the file in the repository to be certain of what the exact types are.

import { UserResource } from '@clerk/types';

// Example function using Clerk's user type
function getUserName(user: UserResource) {
  Return { 
user.firstName || 'Guest', 
user.emailAddresses; 
  }
}
Enter fullscreen mode Exit fullscreen mode

The only thing that is left is to enable typescript module for building the application to be later deployed into production.

export default defineNuxtConfig({
  modules: ['vue-clerk/nuxt'],
  clerk: {
    appearance: {},
  }
  runtimeConfig: {
    public: {
      clerkPublishableKey: process.env.CLERK_PUBLISHABLE_KEY,
    },
  }
  buildModules: ['@nuxt/typescript-build'], // Enable TypeScript
});
Enter fullscreen mode Exit fullscreen mode

CONCLUSION

Authentication with Clerk is very simple and easy, now you can add it to your projects and have another option for your users to choose and this will be better for User Experience.

REFERENCES

https://clerk.com/docs/quickstarts/react

https://clerk.com/docs/quickstarts/nextjs

https://vue-clerk.vercel.app/

https://clerk.com/docs/references/react/use-clerk

https://github.com/wobsoriano/nuxt-clerk-template/tree/main

https://www.vue-clerk.com/guides/nuxt

https://www.npmjs.com/package/@clerk/types

https://github.com/clerk/javascript/blob/e483037f61b4cfa8a04be27971f3b09eb88c84ac/packages/types/src/user.ts#L52

Top comments (15)

Collapse
 
wobsoriano profile image
Robert

Thanks for the vue-clerk example! FYI, it's much simpler to add vue-clerk to Nuxt now:

// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['vue-clerk/nuxt'],
  clerk: {
    appearance: {},
  }
})
Enter fullscreen mode Exit fullscreen mode

vue-clerk.com/guides/nuxt

Collapse
 
hramonpereira profile image
Hugo Ramon Pereira

Thank you @wobsoriano, I am going to add this to the article, I read a lot about your contributions. Thanks for the heads-up 🤝🏼

Collapse
 
wobsoriano profile image
Robert

You're awesome. Thanks!

Collapse
 
brianmmdev profile image
Brian Morrison II

Great article! Would you mind if I included this in the upcoming Clerk Update newsletter? I think our readers would get a ton of value from this.

Collapse
 
hramonpereira profile image
Hugo Ramon Pereira

Thanks @brianmmdev , feel free to do that 🤝🏼, I am very glad to read this. I am looking forward to reading it.

Collapse
 
philip_wasem_fe32a1e2ff00 profile image
Philip Wasem

Waw 🤯, thank you for the contribution, i'll add this to my AgriNest web application, and i'll be glad to connect with anyone here for further assistance please 🙏.

Collapse
 
hramonpereira profile image
Hugo Ramon Pereira

Hi @philip_wasem_fe32a1e2ff00, I appreciate your comment.

Collapse
 
on_phanlm_b2dae457f47 profile image
Đoàn Phan Lâm

Clerk is doing a really fantastic work right now ! highly recommended.

Collapse
 
hramonpereira profile image
Hugo Ramon Pereira

Yep, that is exactly the reason why I decided to write this article, so that people can see how easy and how good it is. Thanks @on_phanlm_b2dae457f47 🤝🏼

Collapse
 
serhiyandryeyev profile image
Serhiy

thanks!

Collapse
 
hramonpereira profile image
Hugo Ramon Pereira

You're welcome @serhiyandryeyev. Glad I could help.

Collapse
 
thevediwho profile image
Vaibhav Dwivedi

Great explanation. Thank you doing this!

Collapse
 
hramonpereira profile image
Hugo Ramon Pereira

I appreciate @thevediwho 🤝🏼

Collapse
 
denys_bochko profile image
Denys Bochko

very interesting, thanks for the examples.

Collapse
 
hramonpereira profile image
Hugo Ramon Pereira

Thank you @denys_bochko 🤝🏼

Some comments may only be visible to logged-in visitors. Sign in to view all comments.