我试图让我的应用程序使用 React,尝试检索用户的 PayPal 电子邮件地址,但我所做的一切都会返回“错误 400 - 错误请求 - 无法获取详细信息来服务请求”。
知道为什么吗?我已经仔细检查了 PayPal 中的返回 URI,以及我的客户/秘密 ID。
我的后端:
export const handlePaypalOAuthCallback = async (req, res) => {
try {
const { code, state } = req.query;
console.log('PayPal callback received:', {
code: code ? 'present' : 'missing',
state: state ? 'present' : 'missing',
fullQuery: req.query
});
if (!code) {
throw new Error('Authorization code not received');
}
if (!state) {
throw new Error('User ID not received in state parameter');
}
const CLIENT_ID = "xxx";
const CLIENT_SECRET = "xxx";
if (!CLIENT_ID || !CLIENT_SECRET) {
console.error('Missing PayPal credentials');
throw new Error('Server configuration error');
}
const auth = Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString('base64');
console.log('Preparing token request:', {
url: 'https://api-m.sandbox.paypal.com/v1/oauth2/token',
grantType: 'authorization_code',
hasCode: !!code,
hasAuth: !!auth,
redirectUri: '<my return uri>/api/paypal/oauth/callback'
});
const params = new URLSearchParams();
params.append('grant_type', 'authorization_code');
params.append('code', code);
params.append('redirect_uri', 'http://dev.gotasker.com.au:4000/api/paypal/oauth/callback');
// Add these additional parameters
params.append('scope', 'openid email');
params.append('client_id', CLIENT_ID);
params.append('client_secret', CLIENT_SECRET);
try {
// Get access token
const tokenResponse = await axios.post(
'https://api-m.sandbox.paypal.com/v1/oauth2/token',
params,
{
headers: {
'Authorization': `Basic ${auth}`,
'Content-Type': 'application/x-www-form-urlencoded',
'PayPal-Request-Id': `${Date.now()}`,
'Accept': 'application/json',
'Accept-Language': 'en_US'
}
}
);
console.log('Token response received:', {
hasAccessToken: !!tokenResponse.data.access_token,
tokenType: tokenResponse.data.token_type,
scope: tokenResponse.data.scope,
status: tokenResponse.status,
headers: tokenResponse.headers
});
const accessToken = tokenResponse.data.access_token;
// Log token details for debugging (first few chars only)
console.log('Access token details:', {
prefix: accessToken.substring(0, 10),
length: accessToken.length,
tokenType: tokenResponse.data.token_type
});
if (!accessToken || typeof accessToken !== 'string') {
throw new Error('Invalid access token received from PayPal');
}
// Make the userInfo request with proper authorization header
const userInfoResponse = await axios.get(
'https://api-m.sandbox.paypal.com/v1/identity/oauth2/userinfo', // Changed URL
{
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json',
'Accept': 'application/json',
'PayPal-Request-Id': `${Date.now()}`,
},
}
);
// Log successful userInfo response
console.log('User info response received:', {
status: userInfoResponse.status,
hasData: !!userInfoResponse.data,
dataKeys: Object.keys(userInfoResponse.data)
});
const paypalEmail = userInfoResponse.data.email;
if (!paypalEmail) {
throw new Error('PayPal email not received in user info response');
}
// Update user with PayPal email
const userId = state;
const user = await UserModel.findById(userId);
if (!user) {
throw new Error('User not found');
}
user.paypalEmail = paypalEmail;
user.paypalVerified = true;
await user.save();
console.log('User PayPal email updated successfully:', {
userId: user._id,
verified: true
});
// Redirect back to frontend with success
res.redirect(`${process.env.FRONTEND_URL}/account?paypal=success`);
} catch (error) {
// Enhanced error logging
console.error('API request failed:', {
status: error.response?.status,
statusText: error.response?.statusText,
data: error.response?.data,
message: error.message,
headers: error.response?.headers,
config: {
url: error.config?.url,
method: error.config?.method,
headers: {
...error.config?.headers,
Authorization: error.config?.headers?.Authorization
? `${error.config.headers.Authorization.substring(0, 10)}...`
: 'missing'
}
},
wwwAuthenticate: error.response?.headers?.['www-authenticate']
});
throw error;
}
} catch (error) {
console.error('PayPal OAuth error:', {
message: error.message,
response: error.response?.data,
status: error.response?.status,
statusText: error.response?.statusText
});
res.redirect(`${process.env.FRONTEND_URL}/account?paypal=error&message=${encodeURIComponent(error.message)}`);
}
};
我的前端:
const PayPalLoginCard = () => {
const { user, updateUserProfile } = useContext(AuthContext);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState('');
const [successMessage, setSuccessMessage] = useState('');
const location = useLocation();
const navigate = useNavigate();
useEffect(() => {
// Handle OAuth response
const searchParams = new URLSearchParams(location.search);
const paypalStatus = searchParams.get('paypal');
if (paypalStatus === 'success') {
setSuccessMessage('PayPal account connected successfully');
// Remove query params
navigate('/account', { replace: true });
} else if (paypalStatus === 'error') {
setError(searchParams.get('message') || 'Failed to connect PayPal account');
navigate('/account', { replace: true });
}
}, [location, navigate]);
const handlePayPalLogin = () => {
try {
const PAYPAL_CLIENT_ID = "xx";
const REDIRECT_URI = 'http://dev.gotasker.com.au:4000/api/paypal/oauth/callback';
const userId = user?.id;
if (!userId) {
throw new Error('User ID not available');
}
// Updated scopes and parameters
const scopes = 'openid email';
const authUrl = `https://www.sandbox.paypal.com/signin/authorize?client_id=${PAYPAL_CLIENT_ID}&response_type=code&scope=${scopes}&redirect_uri=${encodeURIComponent(REDIRECT_URI)}&state=${userId}&nonce=${Date.now()}`;
window.location.href = authUrl;
} catch (error) {
console.error('Error initiating PayPal login:', error);
setError(error.message || 'Failed to initiate PayPal login');
}
};
const handleDisconnect = async () => {
setIsLoading(true);
setError('');
setSuccessMessage('');
try {
const response = await axios.post(
'http://dev.gotasker.com.au:4000/api/paypal/disconnect',
{},
{
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
},
}
);
if (response.data.success) {
await updateUserProfile({ paypalEmail: null });
setSuccessMessage('PayPal account disconnected successfully');
}
} catch (error) {
setError('Failed to disconnect PayPal account');
} finally {
setIsLoading(false);
}
};
我已经验证了我的客户端/秘密 ID,我已经三次检查了我的返回 URI。
<[电子邮件受保护] ><4180068332><01783438295><