next-auth with googleProvider returns error: TIMED OUT // Try signing in with a different account - google-signin

Hi I am working with next.js with next-auth googleProvider.
I have finished coding in local environment and now I am testing in production.
The problem I faced is it google API returns an error when try to signIn. The symptom is like below
it prints "Try signing in with a different account." in the browser
it returns error message like below in server
>>>> redirect callback /welcome http://test.abc.com:5000
[next-auth][error][GET_AUTHORIZATION_URL_ERROR]
https://next-auth.js.org/errors#get_authorization_url_error connect ETIMEDOUT 172.217.26.237:443 {
message: 'connect ETIMEDOUT 172.217.26.237:443',
stack: 'Error: connect ETIMEDOUT 172.217.26.237:443\n' +
' at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1187:16)',
name: 'Error'
}
[next-auth][error][SIGNIN_OAUTH_ERROR]
https://next-auth.js.org/errors#signin_oauth_error connect ETIMEDOUT 172.217.26.237:443 {
error: {
message: 'connect ETIMEDOUT 172.217.26.237:443',
stack: 'Error: connect ETIMEDOUT 172.217.26.237:443\n' +
' at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1187:16)',
name: 'Error'
},
provider: {
id: 'google',
name: 'Google',
type: 'oauth',
wellKnown: 'https://accounts.google.com/.well-known/openid-configuration',
authorization: { params: [Object] },
idToken: true,
checks: [ 'pkce', 'state' ],
profile: [Function: profile],
clientId: 'private.info.apps.googleusercontent.com',
clientSecret: 'user_secret',
httpOptions: { timeout: 6000000, agent: false },
signinUrl: 'http://test.abc.com:5000/api/auth/signin/google',
callbackUrl: 'http://test.abc.com:5000/api/auth/callback/google'
},
message: 'connect ETIMEDOUT 172.217.26.237:443'
}
So... at first, I guess it is a firewall issue. However I could receive data from google endpoints.(i.e. curl https://accounts.google.com/.well-known/openid-configuration)
I was also able to fetch curl 172.217.26.237:443, but it returned zero bytes.
Below is my [...nextAuth.js].(Nothing special I think)
import NextAuth from 'next-auth';
import GoogleProvider from 'next-auth/providers/google';
const AUTH_TIMEOUT = 60000;
export default NextAuth({
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
authorization: {
params: {
prompt: 'consent',
access_type: 'offline',
response_type: 'code',
},
},
// https://github.com/nextauthjs/next-auth/issues/3920
httpOptions: {
timeout: AUTH_TIMEOUT,
},
}),
],
callbacks: {
async signIn({ account, profile }) {
console.debug('>>>> signIn callback', account, profile);
if (account.provider === 'google') {
return profile.email_verified && profile.email.endsWith('myhost.com');
}
return false;
},
async redirect({ url, baseUrl }) {
console.log(process.env.HTTPS_PROXY);
console.debug('>>>> redirect callback', url, baseUrl);
if (url.startsWith('/')) return `${baseUrl}${url}`;
if (new URL(url).origin === baseUrl) return url;
return baseUrl;
},
async session({ session, user, token }) {
console.debug('>>>> session callback', session, user, token);
const mergedSession = { ...session };
if (token && token.id_token) {
mergedSession.user.id_token = token.id_token;
}
return mergedSession;
},
async jwt({
token, user, account,
profile, isNewUser,
}) {
console.debug('>>>> jwt callback', token, user, account, profile, isNewUser);
const mergedTokenObject = { ...token };
if (account && !token.id_token) {
mergedTokenObject.id_token = account.id_token;
}
return mergedTokenObject;
},
},
secret: process.env.APP_SECRET,
});
Here is the question.
Could it be a firewall issue? - I just do not get it since I can fetching some data from those urls with curl.
If not, what kind of things I could try at this moment? thx

Related

next-auth.session-token invalid signature on jwt.io

Did someone encounter similar errors when trying to decode your next-auth.session-token on jwt.io? I followed a video and tried copy my session token to jwt.io to see it, but all i get is an error saying "Invalid signature"
What did i miss here?
[...nextauth].tsx file
import NextAuth, { NextAuthOptions } from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
const authOptions: NextAuthOptions = {
session: {
strategy: "jwt",
},
providers: [
CredentialsProvider({
type: "credentials",
credentials: {},
authorize(credentials, req) {
const { email, password } = credentials as {
email: string;
password: string;
};
//Perform your login logic here
//Find out user from db
if (email !== "john#gmail.com" || password !== "1234") {
throw new Error("Invalid credentials");
}
//If everything is fine
return { id: "1234", name: "John Doe", email: "john#gmail.com" };
},
}),
],
pages: {
signIn: "/auth/signin",
},
};
export default NextAuth(authOptions);
Cookie image
jwt io image

How to get accessToeken in NextAuth?

I am trying to implement a traditional authentication setup with NextAuth. The backend is sending a response like the below after a successful login. The library looks excellent but I don't see where the raw accessToken is saved or any way to get this. I need to add it with every request header I send to the backend. How to deal with this kind of authentication? I would be pleased if you spent some of your time helping me in this regard.
Backend Response after login. FYI I can change the response if need
{
"statusCode": 200,
"data": {
"accesstoken": "eyJhbGcicCI6IkpXVCJ9.eyJlbWFpbCI6ImFzaWY.......",
"user": {
"name": "Participant",
"image": "https://i.pravatar.cc/150?img=4",
"email": "asif.saho#gmail.com"
}
}
}
This is what my [...nextauth].ts looks like.
import axios from 'axios';
import NextAuth, { Session, User } from 'next-auth';
import { JWT } from 'next-auth/jwt';
import CredentialsProvider from 'next-auth/providers/credentials';
import { AUTH_CONST } from '../../../constants/authConst';
import { log } from '../../../services/logger';
const providers = [
CredentialsProvider({
type: 'credentials',
id: 'credentials',
name: 'credentials',
credentials: {
email: { label: 'email', type: 'email' },
password: { label: 'password', type: 'password' },
},
authorize: async (_credentials, req) => {
const res: Response = await axios.post(AUTH_CONST.signInBeUrl, {
email: req.query!.email,
password: req.query!.password,
});
if (res.data.statusCode === 200) {
return res.data.data.user;
}
return null;
},
}),
];
const logger = {
error(code: any, metadata: any) {
log.error('next auth', JSON.stringify(code, null, 2));
log.error('next auth', JSON.stringify(metadata, null, 2));
},
warn(code: any) {
log.warn('next auth', JSON.stringify(code, null, 2));
},
debug(code: any, metadata: any) {
log.info('next auth', JSON.stringify({ code, metadata }, null, 2));
},
};
export default NextAuth({
secret: process.env.SECRET,
providers,
debug: process.env.AUTH_DEBUG === 'true',
logger,
pages: {
signIn: AUTH_CONST.signIn,
signOut: AUTH_CONST.signOut,
error: AUTH_CONST.error,
},
});
With NextAuth, you can use the session strategy as jwt. This is the default. The session is saved in a cookie and never persisted anywhere.
session: {
strategy: "jwt"
}
You can add an API handler that accepts the token and sets it to the cookie.
For example
export default function handler(req, res) {
const { token } = req.body;
res.setHeader('Set-Cookie', `token=${token}`);
res.json({});
}
The cookie is attached to all the requests sent to your backend.
// This is an example of how to read a JSON Web Token from an API route
import { getToken } from "next-auth/jwt"
export default async (req, res) => {
const token = await getToken({ req })
if (token) {
// Signed in
console.log("JSON Web Token", JSON.stringify(token, null, 2))
} else {
// Not Signed in
res.status(401)
}
res.end()
}
Example is taken from the NextAuth doc.

Getting internal server error in next auth provider and session

I have been working on next-auth. I am using google and facebook authentication.
It is working on local but on production it throws 500 internal server error
import Providers from "next-auth/providers";
const options = {
providers: [
Providers.Google({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
}),
Providers.Facebook({
clientId: process.env.FB_CLIENT_ID,
clientSecret: process.env.FB_CLIENT_SECRET,
}),
],
secret: process.env.NEXTAUTH_SECRET,
callbacks: {
async jwt(token, user, account) {
if (user && account) {
token = { ...token, ...user, ...account }
}
return token
},
async session(session, token) {
session.token = token
return Promise.resolve(session)
}
},
};
export default (req, res) => NextAuth(req, res, options);
This is production provider call that throw 500

Next-auth session not created using email verification

I'm creating a web app with nextjs next-auth and have a problem. When user clicks sign in button they are directed to the email form which is okay then when you enter email the email is sent successfully, but when you click sign in from the email you are redirected to the main page but still not signed in. IN the console i get this error:
[next-auth][error][session_error]
https://next-auth.js.org/errors#session_error TypeError: Cannot read property 'name' of undefined
at Object.session (/home/dennis/shopsms/node_modules/next-auth/dist/server/routes/session.js:87:24)
[next-auth][error][session_error]
https://next-auth.js.org/errors#session_error TypeError: Cannot read property 'name' of undefined
at Object.session (/home/dennis/shopsms/node_modules/next-auth/dist/server/routes/session.js:87:24)
[next-auth][error][session_error]
https://next-auth.js.org/errors#session_error TypeError: Cannot read property 'name' of undefined
at Object.session (/home/dennis/shopsms/node_modules/next-auth/dist/server/routes/session.js:87:24)
This is my nextauth.js
// pages/api/auth/[...nextauth].js
import NextAuth from 'next-auth';
import Providers from 'next-auth/providers'
const options = {
site: process.env.NEXTAUTH_URL,
providers: [
Providers.Email({
name:'userauth',
server: {
port: 465,
host: 'smtp.gmail.com',
secure: true,
auth: {
user: process.env.EMAIL_USERNAME,
pass: process.env.EMAIL_PASSWORD,
},
tls: {
rejectUnauthorized: false,
},
},
session: {
jwt: true,
// Seconds - How long until an idle session expires and is no longer valid.
maxAge: 30 * 24 * 60 * 60, // 30 days
},
from: process.env.EMAIL_FROM,
})
],
callbacks: {
session: async (session, user) => {
const { getUserByEmail } = await adapter.Default({}).getAdapter()
const { id } = await getUserByEmail(session.user.email)
session.user.id = id
return session
}
},
database: process.env.DATABASE_URL
}
export default (req, res) => NextAuth(req, res, options)
What could be wrong?
i think you need to specify the returned object like this
return {name: session.user.name, email: session.user.email}
on the page where you need to check if user is signed in
import { useSession } from 'next-auth/client'
const [ session, loading ] = useSession()
console.log(session)
or server side
import { getSession } from 'next-auth/client'
export default async (req, res) => {
const session = await getSession({ req })
/* ... */
res.end()
}
what do you get?

How to implement credentials authorization in Next.js with next-auth?

I try to get credentials auth with next-auth, but I have no experience to use it and whatever I do, i get following message:
[next-auth][error][callback_credentials_jwt_error] Signin in with credentials is only supported if JSON Web Tokens are enabled
https://next-auth.js.org/errors#callback_credentials_jwt_error
This is my src/pages/api/auth/[...nextauth].js file.
import NextAuth from 'next-auth'
import Providers from 'next-auth/providers'
import User from "#models/User"
const options = {
NEXTAUTH_URL:process.env.NEXTAUTH_URL,
providers: [
Providers.Credentials({
// The name to display on the sign in form (e.g. 'Sign in with...')
name: 'Avista',
// The credentials is used to generate a suitable form on the sign in page.
// You can specify whatever fields you are expecting to be submitted.
// e.g. domain, username, password, 2FA token, etc.
credentials: {
email: {label: "Email", type: "text"},
password: {label: "Password", type: "password"}
},
authorize: async (credentials) => {
// Add logic here to look up the user from the credentials supplied
// const user = {id: 1, name: 'J Smith', email: 'jsmith#example.com'}
const user = await User.findOne()
console.log("Данные входа", credentials)
if (user) {
// Any object returned will be saved in `user` property of the JWT
return Promise.resolve(user)
} else {
// If you return null or false then the credentials will be rejected
return Promise.resolve(null)
// You can also Reject this callback with an Error or with a URL:
// return Promise.reject(new Error('error message')) // Redirect to error page
// return Promise.reject('/path/to/redirect') // Redirect to a URL
}
}
}),
Providers.Email({
server: {
host: process.env.EMAIL_SERVER_HOST,
port: process.env.EMAIL_SERVER_PORT,
auth: {
user: process.env.EMAIL_SERVER_USER,
pass: process.env.EMAIL_SERVER_PASSWORD
}
},
from: process.env.EMAIL_FROM
}),
],
// A database is optional, but required to persist accounts in a database
database: process.env.MONGO_URI,
secret: process.env.JWT_SIGNING_PRIVATE_KEY,
},
}
I don't know what I do wrong.
try adding this to your [...nextauth].js page
session: {
jwt: true,
// Seconds - How long until an idle session expires and is no longer valid.
maxAge: 30 * 24 * 60 * 60, // 30 days
},
read more about the options here: https://next-auth.js.org/configuration/options#jwt
This might be useful for someone else.
You need to specify that you want to use the jwt auth style.
Make options.session to be:
{ jwt: true }
If you using next-auth version 4, you should instead do:
{ strategy: 'jwt'}
Add this after providers: []
callbacks: {
jwt: async ({ token, user }) => {
user && (token.user = user)
return token;
},
session: async ({ session, token }) => {
session.user = token.user
return session;
}
},
secret: "secret",
jwt: {
secret: "ksdkfsldferSDFSDFSDf",
encryption: true,
},

Resources