OAuth应用中如何将Express服务端的访问令牌传递给React应用
方案1:最优安全方案 - 前端请求全部走Express代理(无需传递token到前端)
该方案Intuit的access token全程只存储在服务端,完全避免前端泄露风险,不需要改动现有OAuth核心逻辑,适配成本最低,是生产环境首选方案。
- 你现有代码里的
/getCompanyInfo就是标准的代理接口逻辑,所有需要调用Intuit API的能力都按这个格式封装成Express接口即可,React侧直接调用你自己的服务端接口,不需要感知Intuit access token的存在 - 你现有代码里用全局变量存储
oauthClient和oauth2_token_json只能支持单用户使用,多用户访问会出现数据串用问题,建议引入express-session把用户token存在各自的会话里:- 先安装依赖:
npm install express-session - 增加session配置:
const session = require('express-session'); app.use(session({ secret: '自定义加密字符串', resave: false, saveUninitialized: true, cookie: { secure: false } // 生产环境需要改为true }))- 修改callback接口逻辑:
app.get('/callback', function(req, res) { // 每个用户请求单独实例化oauthClient,不要用全局变量 const oauthClient = new OAuthClient({ clientId: '*****', clientSecret: '*****', environment: 'sandbox', redirectUri: 'http://localhost:8000/callback' }); oauthClient.createToken(req.url) .then(function(authResponse) { // 把token存在当前用户的session里,多用户互不干扰 req.session.oauthToken = authResponse.getJson(); req.session.oauthClient = oauthClient; }) .catch(function(e) { console.error(e); }); res.redirect('http://localhost:3000') });- 可以加一个状态接口给前端判断授权状态:
app.get('/auth/status', (req, res) => { res.send({ isAuthenticated: !!req.session.oauthToken }) }) - 先安装依赖:
- React侧因为已经配置了代理到8000端口,直接调用
fetch('/getCompanyInfo')这类自定义接口即可,不需要处理任何token逻辑。
方案2:需要把token传到前端的实现
如果确实有前端直接调用Intuit API的需求,可按以下步骤实现:
步骤1:服务端加密token为JWT传递给前端
- 安装JWT依赖:
npm install jsonwebtoken - 修改callback接口,跳转时附带加密后的JWT参数:
const jwt = require('jsonwebtoken'); app.get('/callback', function(req, res) { const oauthClient = new OAuthClient({ clientId: '*****', clientSecret: '*****', environment: 'sandbox', redirectUri: 'http://localhost:8000/callback' }); oauthClient.createToken(req.url) .then(function(authResponse) { const tokenData = authResponse.getJson(); // 生成JWT,过期时间和Intuit原生token保持一致 const frontToken = jwt.sign(tokenData, 'JWT加密密钥', { expiresIn: tokenData.expires_in }); // 跳转时把JWT带到前端 res.redirect(`http://localhost:3000?token=${frontToken}`) }) .catch(function(e) { console.error(e); res.redirect('http://localhost:3000?error=auth_failed') }); });
步骤2:React侧接收存储token
在React入口文件的初始化逻辑里获取并存储token:
// App.js的useEffect钩子中添加 useEffect(() => { const urlParams = new URLSearchParams(window.location.search); const token = urlParams.get('token'); if (token) { // 存储到localStorage localStorage.setItem('intuit_jwt', token); // 清除URL里的token参数,避免用户分享链接泄露凭证 window.history.replaceState({}, document.title, window.location.pathname); } }, [])
步骤3:前端使用token
调用Intuit API前解密JWT获取原始凭证即可:
import jwtDecode from 'jwt-decode'; const getIntuitToken = () => { const jwt = localStorage.getItem('intuit_jwt'); return jwt ? jwtDecode(jwt) : null; }
注意:该方案token存在前端有XSS攻击泄露风险,处理敏感数据的生产环境不建议使用。
内容的提问来源于stack exchange,提问作者Josh Simon
相关产品推荐
相关产品推荐

