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
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))
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
.
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 }>
}
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:
/api/auth/[providerName]/login
- URL to initiate login/api/auth/[providerName]/callback
- Callback URL to complete login
For example with GitHubProvider
provider, the URLs for GitHub login
will be:/api/auth/github/login
- URL to initiate login/api/auth/github/callback
- Callback URL to complete login You can
determine the provider
with the argument passed to the common
callback.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: [
/*...*/
],
})
)
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
.
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>
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.
To create a new Blitz session, you need to call the use the session
argument passed to the callback function.
session.$create({
...
})
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()
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
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.
redirectUrl
return to the required URL depending on the providerreturn { redirectUrl: "/github" }
Add a redirectUrl
query parameter to the "initiate login" url
example.com/api/auth/github?redirectUrl=/dashboard
example.com/api/auth/github?redirectUrl=${router.pathname}
Via the config passed to NextAuthAdapter
config.successRedirectUrl
config.errorRedirectUrl