auth0 / passport-linkedin-oauth2

Passport Strategy for LinkedIn OAuth 2.0
MIT License
119 stars 106 forks source link

InternalOAuthError: failed to fetch user profile (status: 403 data: {"serviceErrorCode":100,"message":"Not enough permissions to access: GET /me","status":403}) #104

Open anuj47billion opened 4 months ago

anuj47billion commented 4 months ago

I want to login with LinkedIn and after doing all the code I am getting an error

InternalOAuthError: failed to fetch user profile (status: 403 data: {"serviceErrorCode":100,"message":"Not enough permissions to access: GET /me","status":403})

After successfully entered the login credentials it gives error.

ticmaisdev commented 4 months ago

this is mainly due to LinkedIn API breaking changes (and this project's maintainers inactivity). user's info should've been fetched from /v2/userinfo.

I've made a patch so we can get back to using OAuth 2.0, temporarily. I am not making pull requests, unless I'm invited to be a maintainer.


follow these steps to apply the patch to your node project:

  1. install pnpm
  2. run under you project's root: pnpm i passport-linkedin-oauth2
  3. create this folder and file at your project's root: patches/passport-linkedin-oauth2@2.0.0.patch
  4. add the following to the bottom of your package.json file and run pnpm i:

image image3)

note: this will only work for scopes: profile, email, openid. it won't fetch profile picture. it will apply email.verified: boolean, though.

ticmaisdev commented 4 months ago

following there's the content of the patch file:

diff --git a/lib/oauth2.js b/lib/oauth2.js
index 15e2ea9e0de028519c676dbabbc4e3409b7a9772..bfb4454b578d323279d36eeaf6970e622f39210e 100644
--- a/lib/oauth2.js
+++ b/lib/oauth2.js
@@ -2,31 +2,10 @@ var util = require('util')
 var OAuth2Strategy = require('passport-oauth2')
 var InternalOAuthError = require('passport-oauth2').InternalOAuthError;

-var liteProfileUrl = 'https://api.linkedin.com/v2/me?projection=(' +
-  'id,' +
-  'firstName,' +
-  'lastName,' +
-  'maidenName,' +
-  'profilePicture(displayImage~:playableStreams)' +
-  ')';
+var liteProfileUrl = 'https://api.linkedin.com/v2/userinfo';

 // Most of these fields are only available for members of partner programs.
-var basicProfileUrl = 'https://api.linkedin.com/v2/me?projection=(' +
-  'id,' +
-  'firstName,' +
-  'lastName,' +
-  'maidenName,' +
-  'profilePicture(displayImage~:playableStreams),' +
-  'phoneticFirstName,' +
-  'phoneticLastName,' +
-  'headline,' +
-  'location,' +
-  'industryId,' +
-  'summary,' +
-  'positions,' +
-  'vanityName,' +
-  'lastModified' +
-  ')';
+var basicProfileUrl = 'https://api.linkedin.com/v2/userinfo';

 function Strategy(options, verify) {
   options = options || {};
@@ -61,28 +40,12 @@ Strategy.prototype.userProfile = function(accessToken, done) {

     try {
       profile = parseProfile(body);
+
+      return done(null, profile)
     } catch(e) {
       return done(new InternalOAuthError('failed to parse profile response', e));
     }

-    if (!this.options.scope.includes('r_emailaddress')) {
-      return done(null, profile);
-    }
-
-    this._oauth2.get(this.emailUrl, accessToken, function (err, body, res) {
-      if (err) {
-        return done(new InternalOAuthError('failed to fetch user email', err));
-      }
-
-      try {
-        addEmails(profile, body);
-      } catch(e) {
-        return done(new InternalOAuthError('failed to parse email response', e));
-      }
-
-      return done(null, profile);
-    }.bind(this));
-
   }.bind(this));
 }

@@ -140,39 +103,27 @@ function parseProfile(body) {

   var profile = { provider: 'linkedin' };

-  profile.id = json.id;
+  profile.id = json.sub;

   profile.name = {
-    givenName: getName(json.firstName),
-    familyName: getName(json.lastName)
+    givenName: json.given_name,
+    familyName: json.family_name
   };

   profile.displayName = profile.name.givenName + ' ' + profile.name.familyName;

   profile.photos = getProfilePictures(json.profilePicture);

+  profile.emails = [
+    {
+      value: json.email,
+      verified: json.email_verified,
+    }
+  ]
+
   profile._raw = body;
   profile._json = json;

   return profile;
 }
-
-function addEmails(profile, body) {
-  var json = JSON.parse(body);
-
-  if(json.elements && json.elements.length > 0) {
-    profile.emails = json.elements.reduce(function (acc, el) {
-      if (el['handle~'] && el['handle~'].emailAddress) {
-        acc.push({
-          value: el['handle~'].emailAddress
-        });
-      }
-      return acc;
-    }, []);
-  }
-
-  profile._emailRaw = body;
-  profile._emailJson = json;
-}
-
 module.exports = Strategy;
DarthSnufkin commented 4 months ago

just change in your package.json "passport-linkedin-oauth2": "git+https://github.com/auth0/passport-linkedin-oauth2",

and re-install

the latest npm package is 2.0.0 in the repo it's 3.0.0

fdorantesm commented 2 months ago

git+https://github.com/auth0/passport-linkedin-oauth2

🤔 I tried that but yarn installed 2.0.0 version.

Naghell commented 2 months ago

just change in your package.json "passport-linkedin-oauth2": "git+https://github.com/auth0/passport-linkedin-oauth2",

and re-install

the latest npm package is 2.0.0 in the repo it's 3.0.0

omg thank you

fdorantesm commented 2 months ago

just change in your package.json "passport-linkedin-oauth2": "git+https://github.com/auth0/passport-linkedin-oauth2", and re-install the latest npm package is 2.0.0 in the repo it's 3.0.0

omg thank you

My mistake. Installed 3.0.0 but still not working. I replaced the strategy for oauth2 and fetch userinfo endpoint manually. Works for me. 👍