next-auth: Auth provider for Linkedin not working

Environment

System: OS: Linux 6.2 Ubuntu 22.04.3 LTS 22.04.3 LTS (Jammy Jellyfish) CPU: (12) x64 AMD Ryzen 5 3600X 6-Core Processor Memory: 2.63 GB / 15.53 GB Container: Yes Shell: 5.1.16 - /bin/bash Binaries: Node: 20.4.0 - /usr/local/bin/node npm: 9.7.2 - /usr/local/bin/npm

Reproduction URL

https://github.com/nextauthjs/next-auth-example

Describe the issue

As per the documentation from Linkedin, I’ve set up a new LinkedIn app, and added “Sign In with LinkedIn using OpenID Connect” as a product.

At first I had some problems when not specifying scope.

providers: [ LinkedIn({ clientId: process.env.LINKEDIN_ID, clientSecret: process.env.LINKEDIN_SECRET, }) ], pages: { signIn: '/register-cv' },

This returns an ‘unauthorized_scope_error’ for r_emailaddress. Managed to fix that issue by providing scopes as per the documentation from Microsoft:

Authenticating Members New members logging in to your service for the first time will need to follow the Authenticating with OAuth 2.0 Guide. When requesting the authorization code in Step 2 of the OAuth 2.0 Guide, make sure you use the OpenID scope openid to get the ID Token. We are also introducing new scopes profile and email.

openid Required to indicate the application wants to use OIDC to authenticate the member. profile Required to retrieve the member’s lite profile including their id, name, and profile picture. email Required to retrieve the member’s email address. After successful authentication, you will receive the member’s access token and ID token.

If your application does not have these permissions provisioned, you can request access through the Developer Portal. Select your app from My Apps, navigate to the Products tab, and request the Sign in with LinkedIn using OpenID Connect product.

Link: https://learn.microsoft.com/en-us/linkedin/consumer/integrations/self-serve/sign-in-with-linkedin-v2

Updated scopes to match the documentation from Microsoft:

LinkedIn({ clientId: process.env.LINKEDIN_ID, clientSecret: process.env.LINKEDIN_SECRET, authorization: { params: { scope: 'openid profile email' } }})

Now getting this error:

https://next-auth.js.org/errors#oauth_callback_error unexpected iss value, expected undefined, got: https://www.linkedin.com { error: RPError: unexpected iss value, expected undefined, got: https://www.linkedin.com at Client.validateJWT (/home/deb/PhpstormProjects/cvmaker/node_modules/openid-client/lib/client.js:931:15) at Client.validateIdToken (/home/deb/PhpstormProjects/cvmaker/node_modules/openid-client/lib/client.js:766:60) at Client.callback (/home/deb/PhpstormProjects/cvmaker/node_modules/openid-client/lib/client.js:505:18) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) at async oAuthCallback (/home/deb/PhpstormProjects/cvmaker/node_modules/next-auth/core/lib/oauth/callback.js:109:16) at async Object.callback (/home/deb/PhpstormProjects/cvmaker/node_modules/next-auth/core/routes/callback.js:52:11) at async AuthHandler (/home/deb/PhpstormProjects/cvmaker/node_modules/next-auth/core/index.js:208:28) at async NextAuthApiHandler (/home/deb/PhpstormProjects/cvmaker/node_modules/next-auth/next/index.js:22:19) at async NextAuth._args$ (/home/deb/PhpstormProjects/cvmaker/node_modules/next-auth/next/index.js:108:14) { name: 'OAuthCallbackError', code: undefined }, providerId: 'linkedin', message: 'unexpected iss value, expected undefined, got: https://www.linkedin.com'

image

How to reproduce

1: Set up new app on Linkedin, add “Sign In with LinkedIn using OpenID Connect” as a product. 2: Add authentication provider for Linkedin:

import LinkedIn from "next-auth/providers/linkedin"

export const authOptions = {
    secret: 'NOT SO SECRET ANYMORE',
    providers: [
        LinkedIn({
            clientId: process.env.LINKEDIN_ID,
            clientSecret: process.env.LINKEDIN_SECRET,
            authorization: { params: { scope: 'openid profile email' } },
        })
    ], pages: {
        signIn: '/register-cv'
    },
}
export default `NextAuth(authOptions);

About this issue

  • Original URL
  • State: closed
  • Created 9 months ago
  • Comments: 61 (15 by maintainers)

Most upvoted comments

SOLVED

After some debugging I managed to solve this. In case anyone else stumbles across this, since it’s not well documented:

If you’re using Linkedin API V2, you do need to add some custom parameters to the Linkedin provider. The original issue was that the expected iss was undefined. Simply add issuer to OAuthConfig for the Linkedin provider:

issuer: 'https://www.linkedin.com'

This triggers a new error: ‘jwks_uri must be configured on the issuer’. Add jwks_endpoint to OAuthConfig:

jwks_endpoint: 'https://www.linkedin.com/oauth/openid/jwks'

Again, this triggers a new error, where nextauth complains that the profile id is missing. Linkedin API V2 use “sub” not “id”. Solved by overriding the profile function in OAuthConfig:

             return {
                    id: profile.sub,
                    name: profile.name,
                    firstname: profile.given_name,
                    lastname: profile.family_name,
                    email: profile.email,
                    image: profile.picture,
                }
            }

Complete working provider for Linkedin using Linkedin API V2:

LinkedIn({
            clientId: process.env.LINKEDIN_ID,
            clientSecret: process.env.LINKEDIN_SECRET,
            authorization: { params: { scope: 'profile email openid' } },
            issuer: 'https://www.linkedin.com',
            jwks_endpoint: "https://www.linkedin.com/oauth/openid/jwks",
            async profile(profile) {
                return {
                    id: profile.sub,
                    name: profile.name,
                    firstname: profile.given_name,
                    lastname: profile.family_name,
                    email: profile.email
                }
            },
        })

@balazsorban44 I understand that auto discovery does not work as of today due to the mismatch in issuer and wellKnown from LinkedIn’s side. But we should be able to bypass discovery and manually configure the endpoints in the default LinkedIn config of the library.

authorization: {
  url: "https://www.linkedin.com/oauth/v2/authorization",
  params: { scope: "openid profile email" },
},
token: {
  url: "https://www.linkedin.com/oauth/v2/accessToken",
},
userinfo: {
  url: "https://api.linkedin.com/v2/userinfo",
},

This should have worked. But @cocoBavan and @Shashwat61 and myself are all stuck at this stage with error:

Error: TODO: Handle OIDC response body error

error {
   error: 'invalid_client',
   error_description: 'Client authentication failed'
}

GET /api/auth/callback/linkedin?code=(code) 302 in 522ms … POST https://www.linkedin.com/oauth/v2/accessToken 401 in 479ms

On checking the details of the request for /v2/accessToken, I can see that there is a field code_verifier going which when removed the API call works successfully.

As mentioned by @som-nitjsr, this code_verifier parameter is not supported, but it is not clear how to disable PKCE.

I actually am in contact with them, I was just busy, the latest reply was pending on my side. 🙈 I replied to them, will see how long it takes to roll out the fix. the conform method will probably still be welcome though!

Might be interesting to check out https://github.com/panva/oauth4webapi/blob/main/docs/variables/experimental_customFetch.md 👀

This issue should be opened again, because every new app using SignIn with Linked will run into this issue (as I did).

Reason: Microsoft has deprecated the old API as of August 1, 2023!

I’d suggest to keep the current LinkedIn provider as is (for all apps using the legacy API), but add a new LinkedInV2 provider for all new apps using the SignIn with OpenID Connect.

Deprecated API:

LinkedIn_deprecated LinkedIn_deplrecated_scopes

New API

LinkedIn_new LinkedIn_new_scopes

Put up a PR with the issuer update: https://github.com/nextauthjs/next-auth/pull/10671

Anyone find the final solution, still facing same error

Did anybody get LinkedIn working for NextAuth.js v5?

With my current code, I get the LinkedIn login page, and a LinkedIn page where I press ‘Allow’ (this also shows it will redirect to localhost). After choosing Allow, my browser (now on http://localhost:3000/api/auth/error?error=Configuration) shows:

Server error There is a problem with the server configuration. Check the server logs for more information.

My logging shows:

GET /api/auth/signin 200 in 9ms
 POST /api/auth/signin/linkedin 302 in 32ms
error {
  error: 'invalid_client',
  error_description: 'Client authentication failed'
}
[auth][error] CallbackRouteError: Read more at https://errors.authjs.dev#callbackrouteerror
[auth][cause]: Error: TODO: Handle OIDC response body error
    at handleOAuth (webpack-internal:///(rsc)/./node_modules/next-auth/node_modules/@auth/core/lib/actions/callback/oauth/callback.js:86:19)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Module.callback (webpack-internal:///(rsc)/./node_modules/next-auth/node_modules/@auth/core/lib/actions/callback/index.js:32:41)
    at async AuthInternal (webpack-internal:///(rsc)/./node_modules/next-auth/node_modules/@auth/core/lib/index.js:39:24)
    at async Auth (webpack-internal:///(rsc)/./node_modules/next-auth/node_modules/@auth/core/index.js:126:34)
    at async C:\Users\Wouter\source\repos\nxt14\node_modules\next\dist\compiled\next-server\app-route.runtime.dev.js:6:53191
    at async e_.execute (C:\Users\Wouter\source\repos\nxt14\node_modules\next\dist\compiled\next-server\app-route.runtime.dev.js:6:44492)
    at async e_.handle (C:\Users\Wouter\source\repos\nxt14\node_modules\next\dist\compiled\next-server\app-route.runtime.dev.js:6:54445)
    at async doRender (C:\Users\Wouter\source\repos\nxt14\node_modules\next\dist\server\base-server.js:1377:42)
    at async cacheEntry.responseCache.get.routeKind (C:\Users\Wouter\source\repos\nxt14\node_modules\next\dist\server\base-server.js:1587:40)
    at async DevServer.renderToResponseWithComponentsImpl (C:\Users\Wouter\source\repos\nxt14\node_modules\next\dist\server\base-server.js:1507:28)
    at async DevServer.renderPageComponent (C:\Users\Wouter\source\repos\nxt14\node_modules\next\dist\server\base-server.js:1924:24)
    at async DevServer.renderToResponseImpl (C:\Users\Wouter\source\repos\nxt14\node_modules\next\dist\server\base-server.js:1962:32)
    at async DevServer.pipeImpl (C:\Users\Wouter\source\repos\nxt14\node_modules\next\dist\server\base-server.js:920:25)
    at async NextNodeServer.handleCatchallRenderRequest (C:\Users\Wouter\source\repos\nxt14\node_modules\next\dist\server\next-server.js:272:17)
    at async DevServer.handleRequestImpl (C:\Users\Wouter\source\repos\nxt14\node_modules\next\dist\server\base-server.js:816:17)
    at async C:\Users\Wouter\source\repos\nxt14\node_modules\next\dist\server\dev\next-dev-server.js:339:20
    at async Span.traceAsyncFn (C:\Users\Wouter\source\repos\nxt14\node_modules\next\dist\trace\trace.js:154:20)
    at async DevServer.handleRequest (C:\Users\Wouter\source\repos\nxt14\node_modules\next\dist\server\dev\next-dev-server.js:336:24)
    at async invokeRender (C:\Users\Wouter\source\repos\nxt14\node_modules\next\dist\server\lib\router-server.js:174:21)
    at async handleRequest (C:\Users\Wouter\source\repos\nxt14\node_modules\next\dist\server\lib\router-server.js:353:24)
    at async requestHandlerImpl (C:\Users\Wouter\source\repos\nxt14\node_modules\next\dist\server\lib\router-server.js:377:13)
    at async Server.requestListener (C:\Users\Wouter\source\repos\nxt14\node_modules\next\dist\server\lib\start-server.js:141:13)
[auth][details]: {
  "provider": "linkedin"
}
 GET /api/auth/callback/linkedin?code=AQQzoxG4FredactedzW8aWageredactedYYmUsHXW3FsgQ9NbredactedwbF8D-TNbs_rdIbCbredactednZ_Dgy2RCZUBUYynredacteddICqBDJNBJhqUtFDDUWCEopZ-oypAH4gni5gN_PRnzmbh1OGgJP8NoxnUnhcAltC0oYz4_f5nA5ipY 302 in 319ms
 GET /api/auth/error?error=Configuration 500 in 12ms

I tried many variants of this code, some resulting in different errors. But still havent seen it working.

LinkedInProvider({
        clientId: process.env.LINKEDIN_CLIENT_ID!,
        clientSecret: process.env.LINKEDIN_CLIENT_SECRET!,
        client: { token_endpoint_auth_method: 'client_secret_post',  },
        authorization: {
          url: 'https://www.linkedin.com/oauth/v2/authorization',
          params: { scope: 'openid profile email' }
        },
        token: {
          url: 'https://www.linkedin.com/oauth/v2/accessToken',
        },
        wellKnown:
          'https://www.linkedin.com/oauth/.well-known/openid-configuration',
          userinfo: {
            url: 'https://api.linkedin.com/v2/userinfo',
            params: {
              projection: ``,
            },
          },
        issuer: 'https://www.linkedin.com/oauth',
        jwks_endpoint: 'https://www.linkedin.com/oauth/openid/jwks',
                
        profile(profile: LinkedInProfile) {
          return {
            id: profile.sub,
            firstName: profile.given_name,
            lastName: profile.family_name,
            email: profile.email,
            image: profile.picture,
          };
        },
        allowDangerousEmailAccountLinking: true
     
    })

I got it working for GitHub, so I am confident that my base setup is correct. The versions I am using:

"@auth/core": "^0.30.0",
"@auth/prisma-adapter": "^2.0.0",
"next": "^14.2.2",
"next-auth": "^5.0.0-beta.16",

I am posting this here since this thread seems very relevant. Any help is appreciated 😃

I set issuer: 'https://www.linkedin.com/oauth' in the LinkedInProvider instead of issuer: 'https://www.linkedin.com', and the error is resolved.

I can confirm this also worked for me. Must be a recent change in the API.

In case anyone comes across it, I had the same workaround in my codebase, until a different but similar error started showing: https://next-auth.js.org/errors#oauth_callback_error unexpected iss value, expected https://www.linkedin.com, got: https://www.linkedin.com/oauth

I set issuer: 'https://www.linkedin.com/oauth' in the LinkedInProvider instead of issuer: 'https://www.linkedin.com', and the error is resolved.

@balazsmeszegeto i tested the token endpoint by passing the different parameters and figured out that code_verifer is not supported.

you can also see that they dont support nonce claim from here https://www.linkedin.com/oauth/.well-known/openid-configuration?_l=en_US

based on these i have written a solution here https://github.com/som-nitjsr/linkedidp

check the latest code LinkedIn openid connect implementation. currently, there are not support the code_verfier parameter and claim dose not return noce. by setting these two parameter shoud work.

options.UsePkce = false;
options.ProtocolValidator.RequireNonce = false;

Putting logs inside node module files and patching things, I managed to get this far.

LinkedInProvider({
      clientId: process.env.LINKEDIN_CLIENT_ID,
      clientSecret: process.env.LINKEDIN_CLIENT_SECRET,
      authorization: {
        url: "https://www.linkedin.com/oauth/v2/authorization",
        params: { scope: "profile email openid" },
      },
      token: {
        url: "https://www.linkedin.com/oauth/v2/accessToken",
      },
      userinfo: {
        url: "https://api.linkedin.com/v2/userinfo",
      },
    })

But, it fails with the Error: TODO: Handle OIDC response body error. So, I believe the token returned is not correct and needs to fixed by Linked In?

@alxwest not really. I’m not sure if @balazsorban44 is still working with LinkedIn for a fix. The other option option would be for someone to work on the conform() method but that’s beyond my current knowledge so, I guess we will have to dig into the issue and hack around Auth.JS to work, even with LinkedIn not being OIDC spec compliant.

Totally get this. At the same time, LinkedIn has proven they give zero cares about their API or conformity. Realistically, they’ll never implement this properly. I’ll take a stab at the conform() method in the next couple of weeks after I get a few things off my plate. Thanks for outlining the suggested fix, @balazsorban44 !

No update, LinkedIn has not answered me yet. I pinged them again.

The solution for them would be a single rewrite from https://www.linkedin.com/.well-known/openid-configuration to https://www.linkedin.com/oauth/.well-known/openid-configuration to be spec-compliant.

When they fix this, the minimal config can simply be:

import LinkedIn from "next-auth/providers/linkedin"
import type { NextAuthConfig } from "next-auth"
export default { providers: [ LinkedIn ] } satisfies NextAuthConfig

The main problem is that LinkedIn is currently not spec-compliant as per the OIDC spec.

https://www.linkedin.com/oauth/.well-known/openid-configuration returns issuer as https://www.linkedin.com while it should be https://www.linkedin.com/oauth, or the https://www.linkedin.com/.well-known/openid-configuration URL should not 404 but return the same as https://www.linkedin.com/oauth/.well-known/openid-configuration does. I reached out to them but haven’t gotten a response yet.

While this is the case, I cannot easily update the default provider config. I’m thinking about adding a new conform() method to issuer, similarly to what token has: https://github.com/nextauthjs/next-auth/blob/26c47a8e1ae3e7b1069878003fe15da4e1a1928b/packages/core/src/providers/oauth.ts#L264C1-L265

Hi everyone, I’m looking into this now. I think I found a bug in the LinkedIn OIDC implementation, I reached out to them and awaiting response.

Please read the error message completely. It says “The redirect_uri does not match the registered” It means that the callbackUrl you passed as parameter in you signIn() function call is not known to LinkedIn. You need to add it to you configuration in LinkedIn.

Is it still working for you guys? Even with the snippet posted, I’m still getting an error: error: invalid_client, error_description: Client authentication failed

(I’ve double checked the client_id and client_secret multiple times already…

Yes, your solution works great. It saved me a lot of time digging deeper myself. 😃