Yandex provider + Adaptor issue (invalid_grant(code has expired))
Provider type
Yandex
Environment
System:
OS: Windows 10 10.0.19045
CPU: (8) x64 AMD Ryzen 5 1400 Quad-Core Processor
Memory: 11.94 GB / 23.93 GB
Binaries:
Node: 20.16.0 - C:\Program Files\nodejs\node.EXE
Yarn: 1.22.21 - ~\AppData\Roaming\npm\yarn.CMD
npm: 10.8.1 - C:\Program Files\nodejs\npm.CMD
Browsers:
Edge: Chromium (127.0.2651.74)
Internet Explorer: 11.0.19041.4355
npmPackages:
@auth/core: ^0.34.2 => 0.34.2
@auth/hasura-adapter: ^1.4.2 => 1.4.2
next: ^14.1.0 => 14.1.0
next-auth: ^4.24.7 => 4.24.7
react: ^18 => 18.3.1
Reproduction URL
https://github.com/KhekhaevSalekh/next-auth-Yandex-issue
Describe the issue
When I use Yandex provider with next-auth all goes well. But when I connect hasura adapter i get error.
The error I get is (invalid_grant(code has expired)). When a new user presses "Sign in" by Yandex he does not go to home page. He appears at sign-in page. Also there is not next-auth.session-token coockie. In the same time all necessary information is written in the database. When he presses "Sign in" by Yandex second time he is on the home page.
With Google and GitHub authorization everything is good. I have checked this behavior on vercel and locally.
How to reproduce
Just start project from Reproduction URL and try to sighin with yandex.
Expected behavior
Normal sign in flow without this error.
The same problem with Yandex provider.
Terminal output:
GET /api/auth/callback/yandex?code=9756967&cid=47kjwvgdk0fxmxmfvuzyd46v2r 200 in 2886ms
error { error: 'invalid_grant', error_description: 'Code has expired' }
[auth][debug]: callback route error details {
"method": "GET",
"query": {
"code": "9756967",
"cid": "47kjwvgdk0fxmxmfvuzyd46v2r"
}
}
[auth][error] CallbackRouteError: Read more at https://errors.authjs.dev#callbackrouteerror
[auth][cause]: Error: TODO: Handle OAuth 2.0 response body error
at handleOAuth (webpack-internal:///(rsc)/./node_modules/@auth/core/lib/actions/callback/oauth/callback.js:112:19)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
...
Also, sometimes there is an error with PKCE verification, but authorization occurs. Quite unstable provider.
[auth][error] InvalidCheck: PKCE code_verifier cookie was missing. Read more at https://errors.authjs.dev#invalidcheck
at Object.use (webpack-internal:///(rsc)/./node_modules/@auth/core/lib/actions/callback/oauth/checks.js:57:19)
Environment
OS: Windows 10
Node: 20.11
Chrome 127.0.6533.120
next-auth: 5.0.0-beta.20
@auth/prisma-adapter: 2.4.2
next: 14.2.5
The same problem with Yandex provider.
Terminal output:
GET /api/auth/callback/yandex?code=9756967&cid=47kjwvgdk0fxmxmfvuzyd46v2r 200 in 2886ms error { error: 'invalid_grant', error_description: 'Code has expired' } [auth][debug]: callback route error details { "method": "GET", "query": { "code": "9756967", "cid": "47kjwvgdk0fxmxmfvuzyd46v2r" } } [auth][error] CallbackRouteError: Read more at https://errors.authjs.dev#callbackrouteerror [auth][cause]: Error: TODO: Handle OAuth 2.0 response body error at handleOAuth (webpack-internal:///(rsc)/./node_modules/@auth/core/lib/actions/callback/oauth/callback.js:112:19) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) ...Also, sometimes there is an error with PKCE verification, but authorization occurs. Quite unstable provider.
[auth][error] InvalidCheck: PKCE code_verifier cookie was missing. Read more at https://errors.authjs.dev#invalidcheck at Object.use (webpack-internal:///(rsc)/./node_modules/@auth/core/lib/actions/callback/oauth/checks.js:57:19)Environment
OS: Windows 10 Node: 20.11 Chrome 127.0.6533.120 next-auth: 5.0.0-beta.20 @auth/prisma-adapter: 2.4.2 next: 14.2.5
I spent about a week troubleshooting this error, and the only workable solution I’ve found so far involves opening a second tab. However, I'm not satisfied with this workaround.
It would be great if the next-auth developers could consider supporting an OAuth flow similar to the one used by the Yandex provider.
The issue originates from the line in the signIn function from next-auth/react/index.js:
window.location.href = url.
To investigate further, you can insert a process.exit() command right before this line and log the URL for different providers (I tested with Google, GitHub, and Yandex). Then, in your browser's console, manually click on the URI. The behavior for Yandex differs from the others. It likely needs something like
window.open(url).
Regarding your second issue related to PKCE, you shouldn’t encounter this error if you haven't modified the default settings for the Yandex provider. Yandex defaults to using checks='state', so perhaps this parameter was changed (by you). Although I haven't extensively used it, even with the checks=['state', 'pkce'] setting, I didn't experience the same error.
I will continue to add different approachs I found in the repository which is attached to this issue (reproduction url). I hope that next-auth developers will answer. Maybe I missed something and the error can be solved straightforward.
The first approach is not acceptable (second tab) because it looks strange relative to the Google or GitHub. I will write second approach. I would like to read your thoughts. Is it acceptable approach? For my local and prod this works fine for now.
- In Yandex Oauth API console for
REDIRECT_URIwe use something like thishttp://localhost:3000/api/customYandex. - In next-auth options configuration file for Yandex provider we use:
Yandex({
clientId: process.env.YANDEX_CLIENT_ID!,
clientSecret: process.env.YANDEX_CLIENT_SECRET!,
authorization:{
params:{
redirect_uri:`${process.env.NEXTAUTH_URL}/api/customYandex`
},
},
allowDangerousEmailAccountLinking: true,
httpOptions: {
timeout: 10000,
},
}),
In openIDClient library there is by default written 10 sec. So maybe there is no need to write timeout: 10000. But when I saw this code for first time this parameter was written already. So I decide to not change this.
- If in this api we write
import {NextRequest, NextResponse } from "next/server";
import { cookies } from 'next/headers';
export async function GET(req : NextRequest) {
const url = new URL(req.url);
console.log('URL', url)
const code = url.searchParams.get('code');
const cid = url.searchParams.get('cid');
const state = url.searchParams.get('state');
const redirectUrl = ${process.env.NEXTAUTH_URL}/api/auth/callback/yandex?code=${code}&cid=${cid}&state=${state};
return NextResponse.redirect(redirectUrl);
}
we get two consols and the error `invalid_grant (code has expired).
- So I change this code like this:
import {NextRequest, NextResponse } from "next/server";
import { cookies } from 'next/headers';
export async function GET(req : NextRequest) {
const url = new URL(req.url);
const code = url.searchParams.get('code');
const cid = url.searchParams.get('cid');
const state = url.searchParams.get('state');
const cookieStore = cookies();
const firstRequestReceived = cookieStore.get('yandex_oauth_first_received');
if (!firstRequestReceived) {
cookieStore.set('yandex_oauth_first_received', 'true', {
maxAge: 15,
path: '/api/customYandex',
});
return new Response(null, { status: 204 });
}
cookieStore.set('yandex_oauth_first_received', 'false', {
maxAge: -1,
path: '/api/customYandex',
});
const redirectUrl = ${process.env.NEXTAUTH_URL}/api/auth/callback/yandex?code=${code}&cid=${cid}&state=${state};
return NextResponse.redirect(redirectUrl);
}
What do you think about it? What problem can arise from this approach?
The approach above works. But 1 of 20 attempts failed. I noted that it is enough to set timer like this:
import { NextResponse } from "next/server";
export async function GET(req) {
const url = new URL(req.url);
const code = url.searchParams.get('code');
const cid = url.searchParams.get('cid');
await new Promise(resolve => setTimeout(resolve, 5000));
const redirectUrl = `http://localhost:3000/api/auth/callback/yandex?code=${code}&cid=${cid}`;
return NextResponse.redirect(redirectUrl);
}
The approach above works. But 1 of 20 attempts failed. I noted that it is enough to set timer like this:
import { NextResponse } from "next/server"; export async function GET(req) { const url = new URL(req.url); const code = url.searchParams.get('code'); const cid = url.searchParams.get('cid'); await new Promise(resolve => setTimeout(resolve, 5000)); const redirectUrl = `http://localhost:3000/api/auth/callback/yandex?code=${code}&cid=${cid}`; return NextResponse.redirect(redirectUrl); }
Thanks for this workaround, it's worked for me. But I noticed that the described problem only occurs when the app starts "cold" (e.g. right after I run next dev and there is no cache for components). Experimentally, I found out that a 3 seconds timeout is enough for me.
I have now also done some research on this issue. Since I also had errors:
- InvalidCheck: pkceCodeVerifier value could not be parsed;
- error { error: 'invalid_grant', error_description: 'Code has expired' }
I tried the solution written here, it works for me so far. My version next-auth: 5.0.0-beta.20. My config YandexProvider:
YandexProvider({
clientId: process.env.YANDEX_CLIENT_ID,
clientSecret: process.env.YANDEX_CLIENT_SECRET,
authorization: {
url: "https://oauth.yandex.ru/authorize",
params: {
scope: "login:info login:email login:avatar",
redirect_uri: `${process.env.AUTH_URL}/custom-yandex`,
},
},
}),
My route: frontend/src/app/next-auth/custom-yandex/route.js
import {NextRequest, NextResponse } from "next/server";
import {cookies} from "next/headers.js";
export async function GET(req) {
console.log('start custom yandex method', req)
const url = new URL(req.url);
const code = url.searchParams.get('code');
const cid = url.searchParams.get('cid');
const state = url.searchParams.get('state');
const cookieStore = cookies();
const firstRequestReceived = cookieStore.get('yandex_oauth_first_received');
if (!firstRequestReceived) {
cookieStore.set('yandex_oauth_first_received', 'true', {
maxAge: 15,
path: '/next-auth/custom-yandex',
});
return new Response(null, { status: 204 });
}
cookieStore.set('yandex_oauth_first_received', 'false', {
maxAge: -1,
path: '/next-auth/custom-yandex',
});
const redirectUrl = `${process.env.AUTH_URL}/callback/yandex?code=${code}&cid=${cid}&state=${state}`;
return NextResponse.redirect(redirectUrl);
}
Logging, now everything is fine. Note the entries last "start custom yandex method" and then run CLEAR_PKCECODEVERIFIER
[auth][debug]: authorization url is ready {
"url": "https://oauth.yandex.ru/authorize?scope=login%3Ainfo+login%3Aemail+login%3Aavatar&redirect_uri=https%3A%2F%2Ftest-domain.com%2Fnext-auth%2Fcustom-yandex&response_type=code&client_id=793142c6b44d49b6818801753ef3db81&code_challenge=fDjrz5fYprQg6TUPk4YWDSPmplC2ru0XUt1qT0BH6tU&code_challenge_method=S256",
"cookies": [
{
"name": "authjs.pkce.code_verifier",
"value": "eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwia2lkIjoicDZlWDZONTVTa1dZdXFDTmxQSGlhdzFHZ1JvbVB4UmJLdXFwZmlvY09wQ0ZEQ1hfVXFzbTdsWlFfaXNkczA1amdSMVptYkdoWUdBN0lnQV9XTWlDcHcifQ..LcAp6mkqFIvKhgz9huKgsg.2ZT8ZE-fjTIx1PdGInZSLbjmXpiehG9akM9w4QhR_-rdk-O1a-oMfAKojnhzqleIIil9d3VgCsesWgDLjLP3TuIEAFkzQmHuZuIycEPmDJGx0Q-xA7PFPhqblNbRVB6Ooj2iiXHcbbueYf5Akm3MafcSJKWncZp1vqXHHdMKI4n82aGUuR6YVdTGIQMUAoEB.4mTeRbGbXD8xZKtIfP1BCqJ2NSseYnVx_5OOl0xN2w4",
"options": {
"httpOnly": true,
"sameSite": "lax",
"path": "/",
"secure": false,
"maxAge": 900,
"expires": "2024-11-21T06:32:11.568Z"
}
}
],
"provider": {
"id": "yandex",
"name": "Yandex",
"type": "oauth",
"authorization": {
"url": "https://oauth.yandex.ru/authorize?scope=login%3Ainfo+login%3Aemail+login%3Aavatar&redirect_uri=https%3A%2F%2Ftest-domain.com%2Fnext-auth%2Fcustom-yandex&response_type=code&client_id=793142c6b44d49b6818801753ef3db81&code_challenge=fDjrz5fYprQg6TUPk4YWDSPmplC2ru0XUt1qT0BH6tU&code_challenge_method=S256"
},
"token": {
"url": "https://oauth.yandex.ru/token"
},
"userinfo": {
"url": "https://login.yandex.ru/info?format=json"
},
"style": {
"bg": "#ffcc00",
"text": "#000"
},
"checks": [
"pkce"
]
}
}
start custom yandex method Request {
method: 'GET',
url: 'https://localhost:3009/next-auth/custom-yandex?code=yqqdsmvvytkorrde&cid=13np5ye03qyr6j65y4e3x7nfxw',
headers: Headers {
connection: 'close',
cookie: 'authjs.csrf-token=4f9bcd528df2e3803803a4a06373f43a36834e6207a9628d517f632aa240cc57%7Cf42140198390c20a65583b7e6e31c0b22a7f7a4636a992449a01b170ae636e3d; authjs.callback-url=https%3A%2F%2Ftest-domain.com%2F; authjs.pkce.code_verifier=eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwia2lkIjoicDZlWDZONTVTa1dZdXFDTmxQSGlhdzFHZ1JvbVB4UmJLdXFwZmlvY09wQ0ZEQ1hfVXFzbTdsWlFfaXNkczA1amdSMVptYkdoWUdBN0lnQV9XTWlDcHcifQ..LcAp6mkqFIvKhgz9huKgsg.2ZT8ZE-fjTIx1PdGInZSLbjmXpiehG9akM9w4QhR_-rdk-O1a-oMfAKojnhzqleIIil9d3VgCsesWgDLjLP3TuIEAFkzQmHuZuIycEPmDJGx0Q-xA7PFPhqblNbRVB6Ooj2iiXHcbbueYf5Akm3MafcSJKWncZp1vqXHHdMKI4n82aGUuR6YVdTGIQMUAoEB.4mTeRbGbXD8xZKtIfP1BCqJ2NSseYnVx_5OOl0xN2w4',
host: 'test-domain.com',
priority: 'u=0, i',
referer: 'https://oauth.yandex.ru/',
'upgrade-insecure-requests': '1',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
'x-forwarded-for': 'ip.ip.ip.ip.ip',
'x-forwarded-host': 'test-domain.com',
'x-forwarded-port': '3009',
'x-forwarded-proto': 'https',
'x-real-ip': 'ip.ip.ip.ip.ip'
},
destination: '',
referrer: 'about:client',
referrerPolicy: '',
mode: 'cors',
credentials: 'same-origin',
cache: 'default',
redirect: 'follow',
integrity: '',
keepalive: false,
isReloadNavigation: false,
isHistoryNavigation: false,
signal: AbortSignal { aborted: false }
}
start custom yandex method Request {
method: 'GET',
url: 'https://localhost:3009/next-auth/custom-yandex?code=yqqdsmvvytkorrde&cid=13np5ye03qyr6j65y4e3x7nfxw',
headers: Headers {
connection: 'close',
cookie: 'yandex_oauth_first_received=true; authjs.csrf-token=4f9bcd528df2e3803803a4a06373f43a36834e6207a9628d517f632aa240cc57%7Cf42140198390c20a65583b7e6e31c0b22a7f7a4636a992449a01b170ae636e3d; authjs.callback-url=https%3A%2F%2Ftest-domain.com%2F; authjs.pkce.code_verifier=eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwia2lkIjoicDZlWDZONTVTa1dZdXFDTmxQSGlhdzFHZ1JvbVB4UmJLdXFwZmlvY09wQ0ZEQ1hfVXFzbTdsWlFfaXNkczA1amdSMVptYkdoWUdBN0lnQV9XTWlDcHcifQ..LcAp6mkqFIvKhgz9huKgsg.2ZT8ZE-fjTIx1PdGInZSLbjmXpiehG9akM9w4QhR_-rdk-O1a-oMfAKojnhzqleIIil9d3VgCsesWgDLjLP3TuIEAFkzQmHuZuIycEPmDJGx0Q-xA7PFPhqblNbRVB6Ooj2iiXHcbbueYf5Akm3MafcSJKWncZp1vqXHHdMKI4n82aGUuR6YVdTGIQMUAoEB.4mTeRbGbXD8xZKtIfP1BCqJ2NSseYnVx_5OOl0xN2w4',
host: 'test-domain.com',
priority: 'u=0, i',
referer: 'https://oauth.yandex.ru/',
'upgrade-insecure-requests': '1',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
'x-forwarded-for': 'ip.ip.ip.ip.ip',
'x-forwarded-host': 'test-domain.com',
'x-forwarded-port': '3009',
'x-forwarded-proto': 'https',
'x-real-ip': 'ip.ip.ip.ip.ip'
},
}
[auth][debug]: USE_PKCECODEVERIFIER {
"value": "eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwia2lkIjoicDZlWDZONTVTa1dZdXFDTmxQSGlhdzFHZ1JvbVB4UmJLdXFwZmlvY09wQ0ZEQ1hfVXFzbTdsWlFfaXNkczA1amdSMVptYkdoWUdBN0lnQV9XTWlDcHcifQ..LcAp6mkqFIvKhgz9huKgsg.2ZT8ZE-fjTIx1PdGInZSLbjmXpiehG9akM9w4QhR_-rdk-O1a-oMfAKojnhzqleIIil9d3VgCsesWgDLjLP3TuIEAFkzQmHuZuIycEPmDJGx0Q-xA7PFPhqblNbRVB6Ooj2iiXHcbbueYf5Akm3MafcSJKWncZp1vqXHHdMKI4n82aGUuR6YVdTGIQMUAoEB.4mTeRbGbXD8xZKtIfP1BCqJ2NSseYnVx_5OOl0xN2w4"
}
[auth][debug]: PARSE_PKCECODEVERIFIER {
"cookie": "eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwia2lkIjoicDZlWDZONTVTa1dZdXFDTmxQSGlhdzFHZ1JvbVB4UmJLdXFwZmlvY09wQ0ZEQ1hfVXFzbTdsWlFfaXNkczA1amdSMVptYkdoWUdBN0lnQV9XTWlDcHcifQ..LcAp6mkqFIvKhgz9huKgsg.2ZT8ZE-fjTIx1PdGInZSLbjmXpiehG9akM9w4QhR_-rdk-O1a-oMfAKojnhzqleIIil9d3VgCsesWgDLjLP3TuIEAFkzQmHuZuIycEPmDJGx0Q-xA7PFPhqblNbRVB6Ooj2iiXHcbbueYf5Akm3MafcSJKWncZp1vqXHHdMKI4n82aGUuR6YVdTGIQMUAoEB.4mTeRbGbXD8xZKtIfP1BCqJ2NSseYnVx_5OOl0xN2w4"
}
[auth][debug]: CLEAR_PKCECODEVERIFIER {
"cookie": {
"name": "authjs.pkce.code_verifier",
"options": {
"httpOnly": true,
"sameSite": "lax",
"path": "/",
"secure": false,
"maxAge": 900
}
}
}
[auth][debug]: authorization result {...}
NOT WORK:
export async function GET(req) {
console.log('start custom yandex method', req)
const url = new URL(req.url);
const code = url.searchParams.get('code');
const cid = url.searchParams.get('cid');
const state = url.searchParams.get('state');
const redirectUrl = `${process.env.AUTH_URL}/callback/yandex?code=${code}&cid=${cid}&state=${state}`;
return NextResponse.redirect(redirectUrl);
}
log:
[auth][debug]: authorization url is ready {
"url": "https://oauth.yandex.ru/authorize?scope=login%3Ainfo+login%3Aemail+login%3Aavatar&redirect_uri=https%3A%2F%2Fgeniy.nomadicdemo.com%2Fnext-auth%2Fcustom-yandex&response_type=code&client_id=793142c6b44d49b6818801753ef3db81&code_challenge=qz-IXk5uyMY_Gt6CgGkar2b8oQ-qcoAiwhVWNw2GF4A&code_challenge_method=S256",
"cookies": [
{
"name": "authjs.pkce.code_verifier",
"value": "eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwia2lkIjoicDZlWDZONTVTa1dZdXFDTmxQSGlhdzFHZ1JvbVB4UmJLdXFwZmlvY09wQ0ZEQ1hfVXFzbTdsWlFfaXNkczA1amdSMVptYkdoWUdBN0lnQV9XTWlDcHcifQ..xnNjFKuPgK7MrycdGPHtHQ.1X9c8al8YxyA12PJW9LIQBjIhg9RyByiFNaBpsMkp_yy6cQb2EO7SwPQp3HbZjXmAaKnb5w8PS4XvIVvvtXWLnPU3FtkfkvZzBeRxMJTGfh_XhkUUykEssPLnuhmzDOxXWKGaOnWmvOOTne59Y5amzCLWAg4F5-LgfW80DuMfH3uRdlSiRKr9pvBt9GOHKOB.LPuD9WaevXyYi2Nxbz8Izxp2VrL_IJqYHyAw1s2BDmw",
"options": {
"httpOnly": true,
"sameSite": "lax",
"path": "/",
"secure": false,
"maxAge": 900,
"expires": "2024-11-21T06:50:27.250Z"
}
}
],
"provider": {
"id": "yandex",
"name": "Yandex",
"type": "oauth",
"authorization": {
"url": "https://oauth.yandex.ru/authorize?scope=login%3Ainfo+login%3Aemail+login%3Aavatar&redirect_uri=https%3A%2F%2Fgeniy.nomadicdemo.com%2Fnext-auth%2Fcustom-yandex&response_type=code&client_id=793142c6b44d49b6818801753ef3db81&code_challenge=qz-IXk5uyMY_Gt6CgGkar2b8oQ-qcoAiwhVWNw2GF4A&code_challenge_method=S256"
},
"token": {
"url": "https://oauth.yandex.ru/token"
},
"userinfo": {
"url": "https://login.yandex.ru/info?format=json"
},
"style": {
"bg": "#ffcc00",
"text": "#000"
},
"checks": [
"pkce"
]
}
}
start custom yandex method Request {
method: 'GET',
url: 'https://localhost:3009/next-auth/custom-yandex?code=2ptako7f65ymll2k&cid=13np5ye03qyr6j65y4e3x7nfxw',
headers: Headers {
cookie: 'authjs.csrf-token=295569ff3192e32ff6a99177c86f0fd979c1368c8c89f6e7c784e15427ab64c4%7Cdef0329c3bf48444bfd5cc67af6e361ad98a7b1bf765f2d4adf61383cd408dc4; authjs.callback-url=https%3A%2F%2Fgeniy.nomadicdemo.com%2F; authjs.pkce.code_verifier=eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwia2lkIjoicDZlWDZONTVTa1dZdXFDTmxQSGlhdzFHZ1JvbVB4UmJLdXFwZmlvY09wQ0ZEQ1hfVXFzbTdsWlFfaXNkczA1amdSMVptYkdoWUdBN0lnQV9XTWlDcHcifQ..xnNjFKuPgK7MrycdGPHtHQ.1X9c8al8YxyA12PJW9LIQBjIhg9RyByiFNaBpsMkp_yy6cQb2EO7SwPQp3HbZjXmAaKnb5w8PS4XvIVvvtXWLnPU3FtkfkvZzBeRxMJTGfh_XhkUUykEssPLnuhmzDOxXWKGaOnWmvOOTne59Y5amzCLWAg4F5-LgfW80DuMfH3uRdlSiRKr9pvBt9GOHKOB.LPuD9WaevXyYi2Nxbz8Izxp2VrL_IJqYHyAw1s2BDmw',
},
}
[auth][debug]: USE_PKCECODEVERIFIER {
"value": "eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwia2lkIjoicDZlWDZONTVTa1dZdXFDTmxQSGlhdzFHZ1JvbVB4UmJLdXFwZmlvY09wQ0ZEQ1hfVXFzbTdsWlFfaXNkczA1amdSMVptYkdoWUdBN0lnQV9XTWlDcHcifQ..xnNjFKuPgK7MrycdGPHtHQ.1X9c8al8YxyA12PJW9LIQBjIhg9RyByiFNaBpsMkp_yy6cQb2EO7SwPQp3HbZjXmAaKnb5w8PS4XvIVvvtXWLnPU3FtkfkvZzBeRxMJTGfh_XhkUUykEssPLnuhmzDOxXWKGaOnWmvOOTne59Y5amzCLWAg4F5-LgfW80DuMfH3uRdlSiRKr9pvBt9GOHKOB.LPuD9WaevXyYi2Nxbz8Izxp2VrL_IJqYHyAw1s2BDmw"
}
[auth][debug]: PARSE_PKCECODEVERIFIER {
"cookie": "eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwia2lkIjoicDZlWDZONTVTa1dZdXFDTmxQSGlhdzFHZ1JvbVB4UmJLdXFwZmlvY09wQ0ZEQ1hfVXFzbTdsWlFfaXNkczA1amdSMVptYkdoWUdBN0lnQV9XTWlDcHcifQ..xnNjFKuPgK7MrycdGPHtHQ.1X9c8al8YxyA12PJW9LIQBjIhg9RyByiFNaBpsMkp_yy6cQb2EO7SwPQp3HbZjXmAaKnb5w8PS4XvIVvvtXWLnPU3FtkfkvZzBeRxMJTGfh_XhkUUykEssPLnuhmzDOxXWKGaOnWmvOOTne59Y5amzCLWAg4F5-LgfW80DuMfH3uRdlSiRKr9pvBt9GOHKOB.LPuD9WaevXyYi2Nxbz8Izxp2VrL_IJqYHyAw1s2BDmw"
}
[auth][debug]: CLEAR_PKCECODEVERIFIER {
"cookie": {
"name": "authjs.pkce.code_verifier",
"options": {
"httpOnly": true,
"sameSite": "lax",
"path": "/",
"secure": false,
"maxAge": 900
}
}
}
[auth][debug]: authorization result {...}
start custom yandex method Request {
method: 'GET',
url: 'https://localhost:3009/next-auth/custom-yandex?code=2ptako7f65ymll2k&cid=13np5ye03qyr6j65y4e3x7nfxw',
headers: Headers {
cookie: 'authjs.csrf-token=295569ff3192e32ff6a99177c86f0fd979c1368c8c89f6e7c784e15427ab64c4%7Cdef0329c3bf48444bfd5cc67af6e361ad98a7b1bf765f2d4adf61383cd408dc4; authjs.callback-url=https%3A%2F%2Fgeniy.nomadicdemo.com%2F; authjs.session-token=eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwia2lkIjoiSU5zVWZRSDhUeTllMnNIMFlNbjY1bmh2dFJScExUQXg5Q3BObnFWaWo0SmlVVHN2bnlQODREbEFMeUZTbV93NjM0QXExa1hUNVhyYUdMS2lQTThNWVEifQ..gOWCrzCpHdCMiRnjR1WdRw.a-TJ0JqQAaFIBrHPlPHxBfb4aaO1fsRruLcqVyMHIKrVUdGQ0K4YGDy2aTHj9zIspJRz6XYHajZBZWgFQIiKAXJZuywy0eX3myz7hEDfXVuh2uoEYFPWOW2K5kTt0edoaXHIwXS__RC5W8-hsKUPbArlikthDWAjZb9-YMj9zQaBoM0GkfceTzaPu3jN2xYbgRh_GLRITzub2D6JH9ewaGTjy35aMkwcTcb4LEmxIBjz4F1mJSBgkZlg4A3BsGM3KNfDQrr7E7-tc5E4sEsi4J9P8rwXhNPkZbtbtE8B3RAMIPonMZvTatV_q9PVxwTcmZSt_JmIN6z-t2wO6qrArNtK1ci5aASEF6ttMiJvyW1Jtdl2RpLAIba72QsPX5qkVkPPoqCjZkq_of9ODSP7g5ZAn3s19i38cpb72RWrLsYAeXWDzREpB776iqkopR9IkL4G_6h9yB5XIujXdDBEbhfkHa3UssOMS33nx7tszAU_FOlD1tn1LfzSESLZAtm9RSOfklIdM1xdFXziBsn0bZA8Qp5A2ZoQyz7ySN3EMlmKcHmsxduQeiv2-9uvGzfrl6xtJ2alnC8Zu2CTben7wb5T3TRB8x3oTBQ4bmpul02xqGgt92iTQRojnbk3Z876cx55ygCokJALAvbwx-TtMOIoGeIgu9b6pYKJNmhLJoQYTJcmjmYOpeI95LbdikwYpCs4lTBz0QfEGUB54OH4RbyvW3449nd3Zie9PKj00XHtWHptOaO_7T2TKdEyejdUN3cvGTCnGlzaKvu6l5E32oMxWDeBOCV3AhSPubZ7JudCFkAJzFE9kp3fZ0Of3gnB.LjZth4QtWHCg-iaYcVZzT6S-7SCPANdi1p_eOiAf_QI',
},
}
[auth][debug]: USE_PKCECODEVERIFIER {}
[auth][debug]: PARSE_PKCECODEVERIFIER {}
[auth][error] InvalidCheck: pkceCodeVerifier value could not be parsed. Read more at https://errors.authjs.dev#invalidcheck
I don't understand why "start custom yandex method" method works after the cookie has been deleted
I have a same problem with keycloack v25 next-auth: 5.0.0-beta.25
After autentificatuion I get https://authjs.dev/reference/core/errors#callbackrouteerror
web:dev: [auth][cause]: ResponseBodyError: server responded with an error in the response body
web:dev: at processGenericAccessTokenResponse
.....
web:dev: "error": "invalid_grant", web:dev: "error_description": "PKCE verification failed: Code mismatch", web:dev: "provider": "keycloak" web:dev:
is it fixed? or how invalid_scope error can be fixed?
is it fixed? or how invalid_scope error can be fixed?
The problem with invalid scope does not related to this issue. If you get this error with Yandex provider then check your settings on https://oauth.yandex.ru. My scope is setting like this.
ok thanks it works
I have this issue too but this code above is now working for me too. Please can anyone tell what im doing wrong.
auth.ts
// auth.ts
import NextAuth from "next-auth";
import { PrismaAdapter } from "@auth/prisma-adapter";
import { PrismaClient } from "@prisma/client";
import authConfig from "./auth.config";
import { getUserById } from "./data/user";
import { Role } from "@/types";
const prisma = new PrismaClient();
export const { auth, handlers, signIn, signOut } = NextAuth({
adapter: PrismaAdapter(prisma),
session: { strategy: "jwt" },
callbacks: {
async jwt({ token }) {
if (!token.sub) return token;
const existingUser = await getUserById(token.sub);
if (!existingUser) return token;
token.role = existingUser.role;
return token;
},
async session({ session, token }) {
if (token.sub && session.user) {
session.user.id = token.sub;
}
if (token.role && session.user) {
session.user.role = token.role as Role;
}
return session;
},
},
...authConfig,
});
auth.config.ts
import type { NextAuthConfig } from "next-auth";
import Google from "next-auth/providers/google";
import Yandex from "next-auth/providers/yandex";
import Resend from "next-auth/providers/resend";
import { sendVerificationRequest } from "./lib/resend/authSendRequest";
export default {
providers: [
Google({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
}),
Yandex({
clientId: process.env.YANDEX_CLIENT_ID,
clientSecret: process.env.YANDEX_CLIENT_SECRET,
authorization: {
params: {
redirect_uri: 'http://localhost:3000/api/customYandex',
},
},
allowDangerousEmailAccountLinking: true,
}),
Resend({
apiKey: process.env.RESEND_API_KEY,
from: "[email protected]",
sendVerificationRequest: async (params) => {
await sendVerificationRequest(params as any);
},
}),
],
} satisfies NextAuthConfig;
app\api\auth[...nextauth]
import { handlers } from "@/auth" // Referring to the auth.ts we just created
export const { GET, POST } = handlers
and i just get [auth][error] TypeError: Invalid URL
@tachyon322 I think the option with customYandex is not reliable in terms of security. error: Invalid URL maybe the problem is that you are testing on localhost. I forgot the documentation a bit, but it seems like Yandex makes a request to your backend. Due to localhost this request is not getting through