Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VK provider not working #11633

Open
degibons opened this issue Aug 19, 2024 · 13 comments
Open

VK provider not working #11633

degibons opened this issue Aug 19, 2024 · 13 comments
Labels
bug Something isn't working good first issue Good issue to take for first time contributors providers

Comments

@degibons
Copy link

Provider type

Vk

Environment

  System:
    OS: Windows 10 10.0.19045
    CPU: (12) x64 AMD Ryzen 5 2600 Six-Core Processor
    Memory: 5.75 GB / 15.93 GB
  Binaries:
    Node: 20.11.0 - C:\Program Files\nodejs\node.EXE
    npm: 10.2.4 - C:\Program Files\nodejs\npm.CMD
    pnpm: 8.15.6 - C:\Program Files\nodejs\pnpm.CMD
  Browsers:
    Edge: Spartan (44.19041.3570.0), Chromium (127.0.2651.74)
    Internet Explorer: 11.0.19041.3570
  npmPackages:
    @auth/prisma-adapter: ^2.4.2 => 2.4.2
    next: 14.2.5 => 14.2.5
    next-auth: ^5.0.0-beta.20 => 5.0.0-beta.20
    react: ^18 => 18.3.1

Reproduction URL

https://github.com/degibons/authjs-vk-issue

Describe the issue

When trying to sign in through a VK provider, an error is displayed
{"error":"invalid_request","error_description":"Code challenge method is unsupported"}

How to reproduce

  • Clone the repository from Reproduction URL and run npm install
  • Create and setup vk app https://id.vk.com/about/business/go
  • Create .env file from .env.example
  • Fill AUTH_VK_ID, AUTH_VK_SECRET variables from created vk app
  • Run docker db container npm run db
  • Push db schema npx prisma db push
  • Run dev app npm run dev
  • Go to localhost and click the button "SignIn"

Expected behavior

Normal sign in flow without this error.

@degibons degibons added bug Something isn't working providers triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime. labels Aug 19, 2024
@MikeVL

This comment has been minimized.

@balazsorban44 balazsorban44 added good first issue Good issue to take for first time contributors and removed triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime. labels Sep 25, 2024
Copy link

This issue was marked with the good first issue label by a maintainer.

This means that it is a good candidate for someone interested in contributing to the project, but does not know where to start.

Have a look at the Contributing Guide first.

This will help you set up your development environment to get started. When you are ready, open a PR, and link back to this issue in the form of adding Fixes #1234 to the PR description, where 1234 is the issue number. This will auto-close the issue when the PR gets merged, making it easier for us to keep track of what has been fixed.

Please make sure that - if applicable - you add tests for the changes you make.

If you have any questions, feel free to ask in the comments below or the PR. Generally, you don't need to @mention anyone directly, as we will get notified anyway and will respond as soon as we can)

Note

There is no need to ask for permission "can I work on this?" Please, go ahead if there is no linked PR 🙂

@rhiskey
Copy link

rhiskey commented Oct 2, 2024

Same issue. Seems like provider errors and inner VK API refactoring. I suppose this bug needs to be addressed not to Auth.js developers but to vk itself.

@NikitaKolchin
Copy link

vk provider needs to be fixed

@Deinoseer
Copy link

i have
{"error":"invalid_request","error_description":"PKCE is unsupported for server-side authorization"}

@pogran
Copy link

pogran commented Nov 8, 2024

how to fix this problem i need vk auth

@pogran
Copy link

pogran commented Nov 8, 2024

you can add this but it not solve problem

VK({
      clientId: process.env.VK_ID,
      clientSecret: process.env.VK_SECRET,
      checks: ['none'],
    }),

@pogran
Copy link

pogran commented Nov 8, 2024

@balazsorban44 can you fix this issue?

@pogran
Copy link

pogran commented Nov 14, 2024

@balazsorban44 you abandoned this module? mb its not to good idea from me to use this new version with this serious bug

@pogran
Copy link

pogran commented Nov 22, 2024

I turn on debug and see this link . i think this bug
image

@artur1214
Copy link

artur1214 commented Nov 26, 2024

I've had same issue, resolved by my own. It is very frustrating for me to explain everything in the 'right way', why things must be done as they are, and not other way, and contibuting code to the repo. Please, someone else, do it.

Here is MY code, which is definetely work with next 14 and next-auth 5:

export const {
  handlers: { GET, POST },
  auth,
  signIn,
  unstable_update,
} = NextAuth({
//...other fields
  providers: [
//... other providers
{
      ...VK({
        clientId: process.env['VK_ID_APP_ID'] as string,
        clientSecret: process.env['VK_ID_PROTECTED_KEY'] as string,
        checks: [],
      }),
      ...{
        userinfo: {
          //Problem is that VK provider works incorrectly
          url: `https://api.vk.com/method/users.get?fields=photo_100&v=5.131`,
          async request(context: any) {
            /*
              Here we store email of user if it presented, because user.get don't return it.
           */
            const email = context.tokens.email || undefined;
            const access_token = context.tokens.access_token;
            const f = await fetch(
              `https://api.vk.com/method/users.get?fields=photo_100&v=5.131&access_token=${access_token}`
            );
            return { ...(await f.json()), email: email };
          },
        },
        profile(result) {
          /*
           * Again, default VK provider just works not as expected, it is why we need to save user data, and also
           * adds email to user.
           *
           * */
          const profile = result.response?.[0] ?? (result.id ? result : {});
          return {
            id: profile.id.toString(),
            name: [profile.first_name, profile.last_name].filter((v) => !!v).join(' '),
            email: result.email || null,
            image: profile.photo_100,
          };
        },
        token: {
          url: 'https://oauth.vk.com/access_token?v=5.131',
          conform: async (r: Response) => {
            /*
             * And yet again base VK provider just don't working.
             * */
            const resp = await r.json();
            return new Response(
              JSON.stringify({
                token_type: 'dpop',
                ...resp,
              }),
              { ...r }
            );
          },
        },
      },
    }]

Several problems fixed here:

  1. We need to disable checks via
checks: []

As I remember, this will fix pkce problem.

  1. Also, I've changed 'conform' method. As I remember, problem was something llike
{"error":"invalid_request","error_description":"Code challenge method is unsupported"}

Or something similar. This happens, because VK now returns it's auth code in a field, which is not expected by oauth proto and nextauth module just not handles it right way by default.

  1. The last problem is that user.get never returns user email. It being returnd with token from request function. this is why we stores it there and later we can get it in profile function.

P.S. Also the problem is VK users can have no email, I handles it this way:

  1. Db email field I made unique, but nullable
  2. I've added email confirmation page and emailConfirmed date.
  3. I've added signIn callback for auth config:
export const {
  handlers: { GET, POST },
  auth,
  signIn,
  unstable_update,
} = NextAuth({
  callbacks: {
    signIn: async ({ user, account, profile }) => {
      if (user.email === undefined) {
         return false;
       }
       return true;
    },
  }
//Other fields

Here is my trick:
I check email for EXACTLY BE undefined. if it is true it means user just not found in database, so user is not signed in.
Otherwise (even if email in null) user is signed in. But for such case I have permission check in my layout:

const session = await auth();
const user = session?.user;
if (session?.user && !session?.user.email && !requestUrl?.includes('/user/verify')) {
    redirect('/user/verify');
}

So, user without email will be redirected to email confirmation page, where I will link email to this user.

But I think this logic is specific for my project, so you can do it by your own. but by default, your code can throw unexpected error if you will login as VK user without email linked.

ANYWAY VK oauth is now considered to be legacy. And you must use VK ID. It has it's own description, and it is not fully oauth compatible.

For now in fact my method is being redirected to VK ID method from VK itself, and after this I handle the code in a right way.

Better solution is to make fully own provider for VK, which will work with VK ID, but auth js seems to be able to work with oauth only comatible providers, so for now we just can't create provider which will handle everything as expected.

For those, who wants to check if my vk auth is really works:

https://baptist-events.website/login

@seneaLL
Copy link

seneaLL commented Nov 26, 2024

Thank you @artur1214 for solving the problem! From myself, I want to add that if someone after applying this solution encounters an error

[auth][cause]: OperationProcessingError: "response" content-type must be application/json

All you need to do is update the next block of code a little:

        token: {
          url: "https://oauth.vk.com/access_token?v=5.131",
          conform: async (r: Response) => {
            const resp = await r.json();

            return new Response(
              JSON.stringify({
                token_type: "dpop",
                ...resp,
              }),
              { ...r },
            );
          },
        },

In this version, this error will no longer occur, and authorization will work correctly

        token: {
          url: "https://oauth.vk.com/access_token?v=5.131",
          conform: async (r: Response) => {
            const resp = await r.json();

            return new Response(
              JSON.stringify({
                token_type: "dpop",
                ...resp,
              }),
              { headers: { "Content-Type": "application/json" }, status: r.status },
            );
          },
        },

@andreynovikov
Copy link

I confirm that current minimal working solution is:

   providers: [
        // other providers
        {
            ...Vk({checks: []}), // Fix: PKCE is unsupported for server-side authorization
            token: {
                url: 'https://oauth.vk.com/access_token?v=5.131',
                conform: async (response) => {
                    const data = await response.json()
                    return new Response(
                        // Fix: OperationProcessingError: "response" body "token_type" property must be a string
                        JSON.stringify({
                            token_type: 'dpop',
                            ...data,
                        }),
                       // Fix: OperationProcessingError: "response" content-type must be application/json
                       { headers: { "content-type": "application/json" }, status: response.status }
                    )
                }
            }
        }
    ]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working good first issue Good issue to take for first time contributors providers
Projects
None yet
Development

No branches or pull requests

10 participants