This guide demonstrates the straightforward approach of incorporating authentication into your Next.js app using the next-auth.js library. While the library provides numerous options (providers), this tutorial focuses on the implementation using Google Provider. You can follow the same approach for other providers as well
First, make sure you have a Next.js application set up. If not, you can create one using the following command:
npx create-next-app my-next-auth-app
cd my-next-auth-app
npm install next-auth
Navigate to your api folder which is inside the pages folder and create an another folder with name auth inside the api folder. Now finally create a file with name [...nextauth].js inside the auth folder.
The filename and folder structure should be likepages/api/auth/[...nextauth].js
Now open the [...nextauth].js and insert the following code
import GoogleProvider from "next-auth/providers/google";
export const authOptions = {
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
})
]
}
In order to use Google Provider, we imported GoogleProvider from next-auth as illustrated above. Similarly you can import for other providers as wellMake sure to set up environment variables for your Google OAuth credentials. You can do this by creating a .env.local file in the root of your project and adding your credentials or you can use next.config.js
file to add your env variables like below
const nextConfig = {
reactStrictMode: true,
env: {
GOOGLE_CLIENT_ID:"dummy.apps.googleusercontent.com",
GOOGLE_CLIENT_SECRET: "dummy-dummy-dummy-dummy",
},
};
module.exports = nextConfig;
To use the Google Provider, first you need to get your clientId and clientSecret from google if you dont have one.
Assuming you already have a Google account, follow these easy steps:Now, Return to the "Credentials" page, and there, click the "Create Credentials" button. A dropdown menu will appear. Choose the "OAuth Client ID" option:
In this page, you'll see a single dropdown field for your application type, which will reveal additional fields based on your selection. Select the "Web Application" option from this dropdown:
Scroll down to the "Authorized redirect URI" section and paste the following URI: http://localhost:3000/api/auth/callback/google and hit the "CREATE" button.
Note:If you want to setup for a production app then this URL should be like 'your-app-url/api/auth/callback/google'Now at last you will see a popup showing your unique client id and client secret. Keep in mind that both are confidential and don't make it publically visible in you application
Generate your secret key by executing the following command in your terminal:
openssl rand -base64 32
This command will generate a unique secret key, keep this as well private and put in your .env file or next.config.js file
const nextConfig = {
reactStrictMode: true,
env: {
NEXTAUTH_SECRET:"put your generated secret key",
GOOGLE_CLIENT_ID:"dummy.apps.googleusercontent.com",
GOOGLE_CLIENT_SECRET: "dummy-dummy-dummy-dummy",
},
};
module.exports = nextConfig;
Now head back to the [...nextauth.js] file inside pages/api directory and add these new code
import GoogleProvider from "next-auth/providers/google";
export const authOptions = {
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
})
],
callbacks: {
async signIn({ user}) {
if (account.provider === "google") {
const response = await fetch(your backend url + "/auth/signup",{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
name: user.name,
email: user.email,
image: user.image,
}),
}
);
if(response.status===200) return true
if (response.status === 500) {
throw new Error("Internal server error");
}
}
}
},
}
The authOptions
object is an object that contains configuration options for authentication. In this object:
providers
: It specifies the authentication providers that your application will support. In this case, it only includes the GoogleProvider.callbacks
: It specifies callback functions that are triggered during the authentication process. This part of the code is incomplete and needs further explanation, which I'll cover in the next point.The signIn
callback function is triggered when a user signs in. Within this function, it checks if the authentication provider used is Google. If it is, it sends a POST request to a backend endpoint for user signup. The user data (name, email, image) is sent in JSON format in the request body. If the signup is successful (response status is 200), it returns true
.
true
return value indicates to NextAuth.js that the authentication is successful. So you should not return anyother return statement if authentication is success.But if you want to handle incorrect authentication or account already exist based on the response from backend, You need to throw a new error inside this function. We will see this in action
//Previous code
callbacks: {
async signIn({ user}) {
//Previous code
if(response.status===200) return true
if (response.status === 500) throw new Error(JSON.stringify(
{error: "Internal server error", routeTo: "signIn",})
);
}
if (response.status===401) throw new Error( JSON.stringify(
{error: "User Exists",routeTo: "signIn"})
);
}
}
},
}
If there is an error from backend or account already exists you can handle the fallback to signup process by throwing the error like above code. Next auth will automatically handle the error fallback logic. But if you want to handle on your own you can create another file with name error.js
in the same directory where the [...nextauth.js] file is placed
You can write any routing or fallback logic as per your own once you familiarized with next auth but for now put the below code to error.js file
export default function handler(req, res) {
try {
const parsedQuery = JSON.parse(req.query.error);
res.redirect(`${'/auth/' + parsedQuery.routeTo}?error=${parsedQuery.error}`);
} catch (error) {
res.redirect(`/auth/signIn?error=${req.query.error}`);
}
}
The above code will route to the signin page with the error in the url as a query params which is passed by the above code. Then you can retrieve the error code and show the error to user using your own functionality
import { signIn } from 'next-auth/react';
function SignInButton() {
const handleSignIn = async () => {
await signIn('google');
// You can replace 'google' with the name of your desired authentication provider
};
return (
<button onClick={handleSignIn}>Sign In with Google</button>
);
}
export default SignInButton;
If you are going to push your code to production then make sure to change the callback url to your production url as mentioned earlier in the section: Setting OAuth2 Consent Screen
Also you need to add your production url with name NEXTAUTH_URL
to .env or next.config.js file like below. next-auth will automatically pick this url in production environment
const nextConfig = {
reactStrictMode: true,
env: {
NEXTAUTH_URL:"https://www.bytes4dev.com"
NEXTAUTH_SECRET:"put your generated secret key",
GOOGLE_CLIENT_ID:"dummy.apps.googleusercontent.com",
GOOGLE_CLIENT_SECRET: "dummy-dummy-dummy-dummy",
},
};
module.exports = nextConfig;
Edit this page