InternalOAuthError:无法使用 Passport.js LinkedIn 策略获取用户个人资料

问题描述 投票:0回答:1

我正在尝试使用 Passport.js 和 Passport-linkedin-oauth2 包在 Node.js 应用程序中实现 LinkedIn 身份验证。成功登录重定向后,我遇到以下错误:

InternalOAuthError: failed to fetch user profile
    at Strategy.<anonymous> (C:\Users\jahed\MdShayemurRahman-github\002-thesis\backend\node_modules\passport-linkedin-oauth2\lib\oauth2.js:57:19)
    at passBackControl (C:\Users\jahed\MdShayemurRahman-github\002-thesis\backend\node_modules\oauth\lib\oauth2.js:132:9)
    at IncomingMessage.<anonymous> (C:\Users\jahed\MdShayemurRahman-github\002-thesis\backend\node_modules\oauth\lib\oauth2.js:157:7)
    at IncomingMessage.emit (node:events:526:35)
    at endReadableNT (node:internal/streams/readable:1408:12)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21)

我已仔细检查我的

clientID
clientSecret
callbackURL
是否与 LinkedIn 开发者平台中的完全匹配。我还确保 LinkedIn 帐户已授予必要的权限。

ScreenShot LinkedIn 开发者平台

以下是相关代码片段:

import express from 'express';
import cors from 'cors';
import passport from 'passport';
import session from 'express-session';

import { Strategy as LinkedInStrategy } from 'passport-linkedin-oauth2';


const app = express();
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(
  session({
    secret: process.env.SESSION_SECRET, 
    resave: false,
    saveUninitialized: false,
    cookie: {
      secure: false, 
    },
  })
);
app.use(passport.initialize());
app.use(passport.session());
passport.serializeUser((user, done) => {
  done(null, user);
});

passport.deserializeUser((user, done) => {
  done(null, user);
});

passport.use(
  new LinkedInStrategy(
    {
      clientID: process.env.LINKEDIN_CLIENT_ID,
      clientSecret: process.env.LINKEDIN_CLIENT_SECRET,
      callbackURL: process.env.LINKEDIN_CALLBACK_URL,
      scope: ['openid', 'profile', 'w_member_social', 'email'],
    },
    (accessToken, refreshToken, profile, done) => {
      return done(null, profile);
    }
  )
);

app.get('/', (req, res) => {
  res.send(
    `<center style="font-size:140%"> <p>LOGIN </p>
      <img style="cursor:pointer;" onclick="window.location='/auth/linkedin'" src="http://bkpandey.com/wp-content/uploads/2017/09/linkedinlogin.png"/>
      </center>
      `
  );
});

app.get('/auth/linkedin', passport.authenticate('linkedin'));

app.get(
  '/auth/linkedin/callback',
  passport.authenticate('linkedin', {
    successRedirect: '/profile',
    failureRedirect: '/',
  })
);

// Route to handle successful authentication
app.get('/profile', (req, res) => {
  res.send('You are authenticated with LinkedIn!');
});


export default app;

我尝试重新启动服务器并使用不同的网络进行测试,但问题仍然存在。可能是什么原因导致此错误?如何解决该错误以成功从 LinkedIn 获取用户个人资料信息?

node.js authentication oauth-2.0 passport.js linkedin-api
1个回答
0
投票

自 2023 年 8 月起,LinkedIn 再次更改了其 API。 OpenID 收集身份验证的范围名称已更改。现在根据this,授权范围是:emailprofileopenid。因此,删除 w_member_social 字段可能对您有帮助。

此外,您的 /auth/linkedin 端点应定义如下状态:

app.get('/auth/linkedin', passport.authenticate('linkedin',  { state: 'WHATEVER' }));

支持此更改的 Passport-linkedin-oauth2 库版本目前尚未作为 npm 包提供。但无论如何,有一种方法可以使用它。 检查这个

最后两点仍然不能完全解决问题。下一步是实现三足的功能。首先,这就是我定义回调 enpoint 的方式:

app.get('/linkedin/callback', middleware, controller.signupThirdPartyHandler);

当请求到达回调端点时,它会在查询参数中附带一个代码,可用于从 linkedin 获取访问令牌。然后,访问令牌可用于获取范围内的用户信息。

export default async function middleware = async (req: any, res: any, next: any) => {
    try {

        const code = await req.query.code;
        const accessData = await getAccessToken(code);
        const userInfo = await getUserInfo(accessData.access_token);

        if (!userInfo) {
            // throw ...
        }

        const data: ThirdPartySignupDto = {
            first_name: userInfo.given_name ? userInfo.given_name : '',
            last_name: userInfo.family_name ? userInfo.family_name : '',
            email: userInfo.email ? userInfo.email : null,
            accessToken: accessData.access_token,
            provider: "linkedin"
        }

        req.body = data;
        next();

    } catch (error) {
        // handle error
    }
}

另外,以下是我上面使用的两种方法的实现:

const getAccessToken = async (code: string) => {
        try {
            const config = {
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded'
                },
                params: {
                    grant_type: 'authorization_code',
                    code: code,
                    client_id: EnvConfig.LINKEDIN_CLIENT_ID,
                    client_secret: EnvConfig.LINKEDIN_CLIENT_SECRET,
                    redirect_uri: EnvConfig.LINKEDIN_CALLBACK_URL,
                }
            }

            const response = await axios.post('https://www.linkedin.com/oauth/v2/accessToken', null, config);
            return response.data;

        } catch (error) {
            console.error('Error:getAccessToken', error);
            // Handle errors
        }
    };
    const getUserInfo = async (token: String) => {
        try {

            const config = {
                headers: {
                    'Authorization': `Bearer ${token}`
                }
            };

            const response = await axios.get('https://api.linkedin.com/v2/userinfo', config);
            return response.data;
        } catch (error) {
            console.log('Error:getUserInfo', error.code);
            // Handle errors
        }
    }

希望它会起作用!

© www.soinside.com 2019 - 2024. All rights reserved.