🚀Announcing Flightcontrol - Easily Deploy Blitz.js and Next.js to AWS 🚀
Back to Documentation Menu

Third Party Login with NextAuth

Topics

Jump to a Topic

Blitz provides an adapter that allows you to use any NextAuth Provider with Blitz session management in any Nextjs application. Blitz session management gives you a lot more flexibility & control than NextAuth does

Setup

1. Add the NextAuth Adapter for next.config.js

const { withNextAuthAdapter } = require("@blitzjs/auth/next-auth")
const { withBlitz } = require("@blitzjs/next")

/**
 * @type {import('@blitzjs/next').BlitzConfig}
 **/
const config = {
  ...
}

module.exports = withBlitz(withNextAuthAdapter(config))

2. Add the NextAuth API Route

Add a new API route at src/pages/api/auth/[...nextauth].ts with the following contents.

// src/pages/api/auth/[...nextauth].ts
import { api } from "src/blitz-server"
import GithubProvider from "next-auth/providers/github"
import GoogleProvider from "next-auth/providers/google"
import { NextAuthAdapter } from "@blitzjs/auth/next-auth"
import db, { User } from "db"
import { Role } from "types"

// Has to be defined separately for `profile` to be correctly typed below
const providers = [
  GithubProvider({
    clientId: process.env.GITHUB_CLIENT_ID as string,
    clientSecret: process.env.GITHUB_CLIENT_SECRET as string,
  }),
  GoogleProvider({
    clientId: process.env.GOOGLE_CLIENT_ID as string,
    clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
  }),
]

export default api(
  NextAuthAdapter({
    successRedirectUrl: "/",
    errorRedirectUrl: "/error",
    providers,
    callback: async (user, account, profile, session) => {
      ...
    },
  })
)

If you need, you can place the api route at a different path but the filename must be [...nextauth].js or [...nextauth].ts.

Config Structure

export type BlitzNextAuthOptions = AuthOptions & {
  // Redirect after successfull authentification
  successRedirectUrl: string
  // Redirect after any intentional or other auth errors
  errorRedirectUrl: string
  secureProxy?: boolean
  callback: (
    user: User,
    account: Account,
    // Automatically Inferred From Providers Declared
    profile: Profile,
    session: SessionContext,
    provider: ProviderName
  ) => Promise<void | { redirectUrl: string }>
}

URLs

The NextAuth adapter adds two API endpoints for each installed strategy. With the handler at src/pages/api/auth/[...nextauth].ts, it adds the following:

  1. /api/auth/[providerName]/login - URL to initiate login
  2. /api/auth/[providerName]/callback - Callback URL to complete login For example with GitHubProvider provider, the URLs for GitHub login will be:
  3. /api/auth/github/login - URL to initiate login
  4. /api/auth/github/callback - Callback URL to complete login You can determine the provider with the argument passed to the common callback.

SSL Proxy Configuration

You may need to set secureProxy option to true in case your app is located behind SSL proxy (Nginx). Proxy should be set to manage forwarded or x-forwarded-proto header correctly.

// src/pages/api/auth/[...nextauth].ts
import { NextAuthAdapter } from "@blitzjs/auth/next-auth"
import { api } from "src/blitz-server"
import db from "db"
export default api(
  NextAuthAdapter({
    successRedirectUrl: "/",
    errorRedirectUrl: "/",
secureProxy: true,
strategies: [ /*...*/ ], }) )

3. Add a Next Auth Provider

Add a provider to the providers array argument for NextAuthAdapter in the API route, and then follow the providers documentation for further setup.

// src/pages/api/auth/[...nextauth].ts
import { api } from "src/blitz-server"
import GithubProvider from "next-auth/providers/github"
import { NextAuthAdapter, BlitzNextAuthOptions } from "@blitzjs/auth/next-auth"
import db, { User } from "db"
import { Role } from "types"

const config: BlitzNextAuthOptions = {
  successRedirectUrl: "/",
  errorRedirectUrl: "/",
providers: [ GithubProvider({ clientId: process.env.GITHUB_CLIENT_ID as string, clientSecret: process.env.GITHUB_CLIENT_SECRET as string, }), ], callback: async (user, account, profile, session, provider) => { let newUser: User try { newUser = await db.user.findFirstOrThrow({ where: { name: { equals: user.name } }, }) } catch (e) { newUser = await db.user.create({ data: { email: user.email!, name: user.name || "unknown", role: "USER", }, }) } await session.$create({ userId: newUser.id, role: newUser.role as Role, source: "github", }) return { redirectUrl: "/github" } //if no return it will default to successRedirectUrl },
} export default api(NextAuthAdapter(config))

Note: The above GitHubProvider example requires your User prisma model to have email String @unique and name String.

3. Log in with this NextAuth Provider

Add a link to your app with URL format of /api/auth/[providerName]/login. For the above GitHub example, the link would be like this:

<a href="/api/auth/github">Log In With GitHub</a>

Detailed Usage Instructions

Upon successful authentication with the third-party, the user will be redirected back to the above auth API route. When that happens, the verify callback will be called. When the verify callback is called, the user has been authenticated with the third-party, but a session has not yet been created for your Blitz app.

Create a Session

To create a new Blitz session, you need to call the use the session argument passed to the callback function.

session.$create({
    ...
})

Return an Error

If instead, you want to prevent creating a session because of some error, then throw an error inside the callback function. Blitz will catch the error and will attach it to the error redirect URL provided.

throw new YourAuthFailureError()

Showing the Error to the User

Any error during this process will be provided as the authError query parameter. For example with errorRedirectUrl = '/' and done(new Error("it broke")), the user will be redirected to:

/?authError=it broke

Post Authentication Redirects

There are four different ways to determine the redirect URL where a user should be sent after they are authenticated. They are listed here in order of priority. A URL provided with method #1 will override all other URLs.

  • Add redirectUrl return to the required URL depending on the provider
return { redirectUrl: "/github" }
  • Add a redirectUrl query parameter to the "initiate login" url

    • Example: example.com/api/auth/github?redirectUrl=/dashboard
    • Example: example.com/api/auth/github?redirectUrl=${router.pathname}
  • Via the config passed to NextAuthAdapter

    • If success, it will use config.successRedirectUrl
    • If error, it will use config.errorRedirectUrl

Idea for improving this page? Edit it on GitHub.