keystone-nextjs-auth
keystone-nextjs-auth copied to clipboard
Invalid Json Response for /api/auth/session
Both in my own application and in the example application, im getting this error. When I run yarn keystone dev
it just goes into an infinite loop of compiling and erroring out.
For all I know im doing something wrong, but I follow the documentation here and I also checked next-auth's documentation and I have googled this issue and found somewhat related issues, but I think its a pretty general error since its just the fetch api not being able to read an expected json output.
Since the unexpected character is <
I assumed the response it was getting was html and when I tried to go, to the page it was trying to get to, it seemed like it was returning an html page saying that I didn't have access to this page. But adding the path to the public pages config did nothing.
Here is my main file, its basically the example project but I changed the database to sqlite because it was easier to run locally that way.
import 'dotenv/config';
import * as Path from 'path';
import { config } from '@keystone-6/core';
import { statelessSessions } from '@keystone-6/core/session';
import Auth0 from '@opensaas/keystone-nextjs-auth/providers/auth0';
import { createAuth } from '@opensaas/keystone-nextjs-auth';
import { KeystoneContext } from '@keystone-6/core/types';
import { lists } from './schemas';
let sessionSecret = process.env.SESSION_SECRET;
if (!sessionSecret) {
if (process.env.NODE_ENV === 'production') {
throw new Error('The SESSION_SECRET environment variable must be set in production');
} else {
sessionSecret = '-- DEV COOKIE SECRET; CHANGE ME --';
}
}
const sessionMaxAge = 60 * 60 * 24 * 30; // 30 days
const auth = createAuth({
listKey: 'User',
identityField: 'subjectId',
sessionData: `id name email`,
autoCreate: true,
resolver: async ({ user, profile }: { user: any; profile: any }) => {
const name = user.name as string;
const email = profile.email as string;
return { email, name };
},
pages: {
signIn: '/admin/auth/signin',
},
keystonePath: '/admin',
sessionSecret,
providers: [
Auth0({
clientId: process.env.AUTH0_CLIENT_ID || 'Auth0ClientID',
clientSecret: process.env.AUTH0_CLIENT_SECRET || 'Auth0ClientSecret',
issuer: process.env.AUTH0_ISSUER_BASE_URL || 'https://opensaas.au.auth0.com',
}),
],
});
export default auth.withAuth(
config({
server: {
cors: {
origin: [process.env.FRONTEND || 'http://localhost:7777'],
credentials: true,
},
},
db: {
provider: 'sqlite',
url: 'file:./keystone.db',
},
ui: {
isAccessAllowed: (context: KeystoneContext) => !!context.session?.data,
publicPages: ['/admin/auth/signin', '/admin/auth/error'],
getAdditionalFiles: [
async () => [
{
mode: 'copy',
inputPath: Path.resolve('./customPages/signin.js'),
outputPath: 'pages/auth/signin.js',
},
{
mode: 'copy',
inputPath: Path.resolve('./customPages/error.js'),
outputPath: 'pages/auth/error.js',
},
],
],
},
lists,
session: statelessSessions({
maxAge: sessionMaxAge,
secret: sessionSecret,
}),
experimental: {
generateNodeAPI: true,
},
})
);
Here is what the whole error log looks like
➜ yarn keystone dev
yarn run v1.22.19
$ /Users/eric/Development/web/keystonejs-auth-test/node_modules/.bin/keystone dev
✨ Starting Keystone
⭐️ Dev Server Starting on http://localhost:3000
⭐️ GraphQL API Starting on http://localhost:3000/api/graphql
✨ Generating GraphQL and Prisma schemas
✨ The database is already in sync with the Prisma schema.
✨ Connecting to the database
✨ Creating server
✅ GraphQL API ready
✨ Generating Admin UI code
✨ Preparing Admin UI app
event - compiled client and server successfully in 7.4s (1263 modules)
✅ Admin UI ready
wait - compiling /no-access (client and server)...
event - compiled client and server successfully in 492 ms (1268 modules)
[next-auth][error][CLIENT_FETCH_ERROR]
https://next-auth.js.org/errors#client_fetch_error invalid json response body at http://localhost:3000/api/auth/session reason: Unexpected token < in JSON at position 0 {
error: {
message: 'invalid json response body at http://localhost:3000/api/auth/session reason: Unexpected token < in JSON at position 0',
stack: 'FetchError: invalid json response body at http://localhost:3000/api/auth/session reason: Unexpected token < in JSON at position 0\n' +
' at /Users/eric/Development/web/keystonejs-auth-test/node_modules/next/dist/compiled/node-fetch/index.js:1:51220\n' +
' at processTicksAndRejections (node:internal/process/task_queues:96:5)',
name: 'FetchError'
},
url: 'http://localhost:3000/api/auth/session',
message: 'invalid json response body at http://localhost:3000/api/auth/session reason: Unexpected token < in JSON at position 0'
}
wait - compiling /api/__keystone_api_build (client and server)...
event - compiled successfully in 129 ms (159 modules)
wait - compiling...
event - compiled client and server successfully in 174 ms (1290 modules)
[next-auth][error][CLIENT_FETCH_ERROR]
https://next-auth.js.org/errors#client_fetch_error invalid json response body at http://localhost:3000/api/auth/session reason: Unexpected token < in JSON at position 0 {
error: {
message: 'invalid json response body at http://localhost:3000/api/auth/session reason: Unexpected token < in JSON at position 0',
stack: 'FetchError: invalid json response body at http://localhost:3000/api/auth/session reason: Unexpected token < in JSON at position 0\n' +
' at /Users/eric/Development/web/keystonejs-auth-test/node_modules/next/dist/compiled/node-fetch/index.js:1:51220\n' +
' at runMicrotasks (<anonymous>)\n' +
' at processTicksAndRejections (node:internal/process/task_queues:96:5)',
name: 'FetchError'
},
url: 'http://localhost:3000/api/auth/session',
message: 'invalid json response body at http://localhost:3000/api/auth/session reason: Unexpected token < in JSON at position 0'
}
Updated, I built and ran it with yarn keystone start
and actually that endpoint is a 404 page, not a no access page.
Oh, I figured it out. It was that I needed to set the NEXTAUTH_URL
because it needs to be /admin/api/auth
not /api/auth
. Pretty new to keystone and im primarily a vue developer so don't have a lot of experience with the base next-auth library. That said, I think NEXTAUTH_URL
should be mentioned in more than just the contributing section and honestly, it might be nice if it the package just checked if you set the NEXTAUTH_URL and if not it set it to /admin/api/auth
because I think that is the default for keystone?
Hey @foopis23
Thanks for posting your solution. NEXTAUTH_URL
should be being set to this default if you don't set it, I'll have to dig around and see why this might not be happening.
I'm having this problem too but with the Azure AD provider. I created a new keystonejs app with the following:
import * as dotenv from 'dotenv';
dotenv.config();
import { config } from '@keystone-6/core';
import { statelessSessions } from '@keystone-6/core/session';
import AzureADProvider from "@opensaas/keystone-nextjs-auth/providers/azure-ad";
import { createAuth } from '@opensaas/keystone-nextjs-auth';
import { lists } from './schema';
let sessionSecret = process.env.SESSION_SECRET;
if (!sessionSecret) {
if (process.env.NODE_ENV === 'production') {
throw new Error('The SESSION_SECRET environment variable must be set in production');
} else {
sessionSecret = '-- DEV COOKIE SECRET; CHANGE ME --';
}
}
const sessionMaxAge = 60 * 60 * 24 * 30; // 30 days
const auth = createAuth({
listKey: 'User',
identityField: 'subjectId',
sessionData: `id name email`,
sessionSecret: sessionSecret,
autoCreate: true,
resolver: async ({user, profile, account}) => {
const username = user.name as string;
const email = user.email as string;
return { email, username };
},
keystonePath: '/admin',
providers: [
AzureADProvider({
clientId: process.env.AZURE_AD_CLIENT_ID,
clientSecret: process.env.AZURE_AD_CLIENT_SECRET,
tenantId: process.env.AZURE_AD_TENANT_ID,
}),
],
});
export default auth.withAuth(
config({
db: {
provider: 'mysql',
url: process.env.DATABASE_URL,
useMigrations: true,
idField: { kind: 'uuid' },
enableLogging: true,
},
lists,
session: statelessSessions({
maxAge: sessionMaxAge,
secret: sessionSecret,
})
})
);
I have tried setting NEXTAUTH_URL
but this doesn't seem to make any difference. I have tried all of:
NEXTAUTH_URL="http://localhost:3000/admin/api/auth"
NEXTAUTH_URL="http://localhost:3000/admin"
NEXTAUTH_URL="http://localhost:3000"
Still receiving the following error:
[next-auth][error][CLIENT_FETCH_ERROR]
https://next-auth.js.org/errors#client_fetch_error invalid json response body at http://localhost:3000/api/auth/session reason: Unexpected token < in JSON at position 0 {
error: {
message: 'invalid json response body at http://localhost:3000/api/auth/session reason: Unexpected token < in JSON at position 0',
stack: 'FetchError: invalid json response body at http://localhost:3000/api/auth/session reason: Unexpected token < in JSON at position 0\n' +
' at /home/enablenz/projects/enzweb/api/node_modules/next/dist/compiled/node-fetch/index.js:1:51220\n' +
' at runMicrotasks (<anonymous>)\n' +
' at processTicksAndRejections (node:internal/process/task_queues:96:5)',
name: 'FetchError'
},
url: 'http://localhost:3000/api/auth/session',
message: 'invalid json response body at http://localhost:3000/api/auth/session reason: Unexpected token < in JSON at position 0'
}
Any idea what I'm doing wrong? 🙂
Hey @earthwytch based on your config NEXTAUTH_URL=http://localhost:3000/admin/api/auth
should work assuming there is nothing overriding the PORT of 3000. What do you see if you open a browser to http://localhost:3000/admin/api/auth ?
Hi @borisno2, I get "You don't have access to this page." which is the same for http://localhost:3000. I feel like I'm just missing one tiny piece of the puzzle 😕
Output from console is the same
yarn run v1.22.19
$ ./node_modules/@keystone-6/core/bin/cli.js dev
✨ Starting Keystone
⭐️ Server listening on :::3000 (http://localhost:3000/)
⭐️ GraphQL API available at /api/graphql
✨ Generating GraphQL and Prisma schemas
✨ Your database is up to date, no migrations need to be created or applied
✨ Connecting to the database
✨ Creating server
✅ GraphQL API ready
✨ Generating Admin UI code
✨ Preparing Admin UI app
event - compiled client and server successfully in 3.5s (1183 modules)
✅ Admin UI ready
wait - compiling /_error (client and server)...
event - compiled client and server successfully in 298 ms (1184 modules)
warn - Fast Refresh had to perform a full reload. Read more: https://nextjs.org/docs/basic-features/fast-refresh#how-it-works
wait - compiling /no-access (client and server)...
event - compiled client and server successfully in 129 ms (1189 modules)
[next-auth][error][CLIENT_FETCH_ERROR]
https://next-auth.js.org/errors#client_fetch_error invalid json response body at http://localhost:3000/api/auth/session reason: Unexpected token < in JSON at position 0 {
error: {
message: 'invalid json response body at http://localhost:3000/api/auth/session reason: Unexpected token < in JSON at position 0',
stack: 'FetchError: invalid json response body at http://localhost:3000/api/auth/session reason: Unexpected token < in JSON at position 0\n' +
' at /home/enablenz/projects/enzweb/api/node_modules/next/dist/compiled/node-fetch/index.js:1:51220\n' +
' at runMicrotasks (<anonymous>)\n' +
' at processTicksAndRejections (node:internal/process/task_queues:96:5)',
name: 'FetchError'
},
url: 'http://localhost:3000/api/auth/session',
message: 'invalid json response body at http://localhost:3000/api/auth/session reason: Unexpected token < in JSON at position 0'
}
[next-auth][error][CLIENT_FETCH_ERROR]
https://next-auth.js.org/errors#client_fetch_error invalid json response body at http://localhost:3000/api/auth/session reason: Unexpected token < in JSON at position 0 {
error: {
message: 'invalid json response body at http://localhost:3000/api/auth/session reason: Unexpected token < in JSON at position 0',
stack: 'FetchError: invalid json response body at http://localhost:3000/api/auth/session reason: Unexpected token < in JSON at position 0\n' +
' at /home/enablenz/projects/enzweb/api/node_modules/next/dist/compiled/node-fetch/index.js:1:51220\n' +
' at runMicrotasks (<anonymous>)\n' +
' at processTicksAndRejections (node:internal/process/task_queues:96:5)',
name: 'FetchError'
},
url: 'http://localhost:3000/api/auth/session',
message: 'invalid json response body at http://localhost:3000/api/auth/session reason: Unexpected token < in JSON at position 0'
}
EDIT: Also, just FYI, these are the env vars I have set... am I missing any?
AZURE_AD_CLIENT_ID=<secret squirrel here>
AZURE_AD_CLIENT_SECRET=<secret squirrel here>
AZURE_AD_TENANT_ID=<secret squirrel here>
DATABASE_URL=<secret squirrel here>
NEXTAUTH_URL=http://localhost:3000/admin/api/auth
NODE_ENV=development
SESSION_SECRET=<secret squirrel here>
Could you try adding isAccessAllowed: (context: KeystoneContext) => !!context.session,
to your config.ui
So that it looks something like
export default auth.withAuth(
config({
db: {
provider: 'mysql',
url: process.env.DATABASE_URL,
useMigrations: true,
idField: { kind: 'uuid' },
enableLogging: true,
},
ui: {
isAccessAllowed: (context: KeystoneContext) => !!context.session,
},
lists,
session: statelessSessions({
maxAge: sessionMaxAge,
secret: sessionSecret,
})
})
);
That moved things along so I now have access to an Azure AD login button 👍
The error still appears in the console, exactly as before (same path, without "admin") but doesn't seem to affect functionality.
[next-auth][error][CLIENT_FETCH_ERROR]
https://next-auth.js.org/errors#client_fetch_error invalid json response body at http://localhost:3000/api/auth/session reason: Unexpected token < in JSON at position 0 {
error: {
message: 'invalid json response body at http://localhost:3000/api/auth/session reason: Unexpected token < in JSON at position 0',
stack: 'FetchError: invalid json response body at http://localhost:3000/api/auth/session reason: Unexpected token < in JSON at position 0\n' +
' at /home/enablenz/projects/test/keystone-azuread/node_modules/next/dist/compiled/node-fetch/index.js:1:51220\n' +
' at processTicksAndRejections (node:internal/process/task_queues:96:5)',
name: 'FetchError'
},
url: 'http://localhost:3000/api/auth/session',
message: 'invalid json response body at http://localhost:3000/api/auth/session reason: Unexpected token < in JSON at position 0'
}
But for me it now hits an error regarding the username field, which appears in the console after going through the Microsoft authentication. No user is created in the database and it just halts at an error screen.
SELECT `db`.`User`.`id`, `db`.`User`.`name`, `db`.`User`.`email`, `db`.`User`.`subjectId`, `db`.`User`.`password`, `db`.`User`.`createdAt` FROM `db`.`User` WHERE `db`.`User`.`subjectId` = ? LIMIT ? OFFSET ? /* traceparent=00-00-00-00 */
GraphQLError: Variable "$data" got invalid value { subjectId: "<a long string id>", email: "<my email address here>", username: "<my user name here>" }; Field "username" is not defined by type "UserCreateInput". Did you mean "name"?
Apologies if this is an unrelated error (due to my lack of knowledge) but hoping you'll see something obvious 🙂
That great! I have just merged #266 which should resolve the error when isAccessAllowed
is not defined.
As for the second error, this would be something in your resolver
function. I am guessing you are passing through a username
field that gets passed into a create
function in the package, however you don't have a username
field in your schema. Feel free to log another issue if you are still stuck, but I will close this one as the original issue has been resolved.