Authentication Scheme
Authentication means verifying that user is valid. Different providers are used for authemtication as mentioned below.- [userid + password==credential provider]
- [social media login - goog/fb/github provider - Oauth2]
- Email Provider
- - After login, server creates sessions and sends session id to the client via cookie. User details are mapped to session id on server
- - Browser automatically sends the session id via cookie on every subsequent request
- - you can invalidate session
- - Generally used in banking apps
- - After successful login, server creates JWT token and sends to the client.
- - Client can send the token in authorization header on every request.
- - Nothing stored on server.
- - need refresh token to keep user logged in
Using libraries
Passportjs - just a library to above things next-authUsing auth service
auth0 - Amazon incognitoNext-Auth
High level steps are mentioned below.- Dependencies - next-auth and mongodb
- Providers - Generate provider (google, github or facebook) client id and secret
- next auth handler endpoint - Add api/auth/[...nextauth].js endpoint
- Then you should be able to go to this sign in page at api/auth/signin
- Add SessionProvider in _app.tsx
- Use session at client side
- Use session at Server Side
- Use adapter if you want to store session and user data in db e.g. mongodb
Dependencies
First you need to install below dependencies
npm i --save next-auth mongodb @next-auth/mongodb-adapter
Provider settings - e.g. github oauth app
- Create oauth app on github at https://github.com/settings/developers
- callback url - /api/auth/callback/github
- Get client id and secret
next-auth handler endpoint
In .env.local file, store the secrets.- provider_client_id
- provider_client_secret
- NEXTAUTH_URL
- auth_secret
- jwt_secret
import NextAuth from 'next-auth'
import AppleProvider from 'next-auth/providers/apple'
import GitHubProvider from 'next-auth/providers/github'
export default (req,res) => NextAuth(req,res, {
providers : [
GitHubProvider({
clientId : process.env.githubClientId,
clientSecret : process.env.githubClientSecret
})],
debug : true,
secret : "authsecrett",
jwt : {
secret : "mysehdihfu"
}
})
Test that api handler is working
Just go to api/auth/signin and provider login buttons should be displayed.Add SessionProvider in _app.tsx
You can use the context provider
import { Layout } from '../components/Layout'
import '../styles/globals.css'
import '../node_modules/highlight.js/styles/magula.css'
import type { AppProps } from 'next/app'
import { SessionProvider } from "next-auth/react"
function MyApp({ Component, pageProps: { session, ...pageProps } }: AppProps) {
return (
<SessionProvider session={session} refetchInterval={5 * 60}>
<Layout>
<Component {...pageProps} />
</Layout>
</SessionProvider>
)
}
export default MyApp
Use Session at client side
import { useSession, getSession } from "next-auth/react"
export default function Page() {
const { data: session, status } = useSession()
if (status === "loading") {
return <p>Loading...</p>
}
if (status === "unauthenticated") {
return <p>Access Denied</p>
}
return (
<>
<h1>Protected Page</h1>
<p>You can view this page because you are signed in.</p>
</>
)
}
Get session data at client side
import { useSession } from 'next-auth/react'
const { data: session, status } = useSession()
if (status==="loading"){
// return (<span>Loading</span>)
return ("<span>Loading</span>")
}
//data: Session / undefined / null
if (!session){
return (<span>Please sign in first</span>)
}
if (session){
return (<>{JSON.stringify(session)}</>)
}
Protecting api routes on server
import { getSession } from "next-auth/react"
export default async (req, res) => {
const session = await getSession({ req })
if (session) {
// Signed in
console.log("Session", JSON.stringify(session, null, 2))
} else {
// Not Signed in
res.status(401)
}
res.end()
}
Getting token from server
import { getToken } from "next-auth/jwt"
const secret = process.env.SECRET
export default async (req, res) => {
const token = await getToken({ req, secret })
if (token) {
// Signed in
console.log("JSON Web Token", JSON.stringify(token, null, 2))
} else {
// Not Signed in
res.status(401)
}
res.end()
}
Database adapter
So far we have not stored session or user information in database. So let's do it now. npm install @prisma/client @next-auth/prisma-adapter npm install prisma --save-devAd