英文:
Google OAuth 2.0 email missing from profile
问题
我正在尝试通过Passport设置Google OAuth 2.0。我正在使用Express开发Node.js应用程序。
Node.js版本:v18.12.1
当用户尚未创建时,我尝试根据Google提供的信息创建用户。但是,出于某种原因,电子邮件丢失了。
我在OAuth 2.0上使用的范围:
问题的代码片段:
passport.use(new googleAuth.Strategy({
clientID: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
callbackURL: "http://localhost:3000/auth/google/secrets",
scope: ["email", "profile"]
},
(accessToken: string, refreshToken: string, profile: googleAuth.Profile, cb: VerifyCallback) => {
User.findOne({googleId: profile.id}, (err: CallbackError, user: PassportLocalModel<IUser>) => {
if(err){
return cb(err);
}else if(user){
return cb(err, user);
}else{
const user = new User({
email: profile.emails![0].value,
googleId: profile.id,
});
user.save((err: CallbackError) => {
if(err){
console.log(err);
cb(err);
}
})
}
})
}
));
Profile.emails和_json.email都未定义(参考:https://developers.google.com/identity/openid-connect/openid-connect#an-id-tokens-payload)
有任何想法吗?
如果需要更多信息,请不要犹豫提问。
谢谢
编辑:
_json的内容(实际内容已隐藏):
_json: {
sub: <某个字符串>,
name: <某个姓名>,
given_name: <某个姓名>,
family_name: <某个姓名>,
picture: <某个网址>,
locale: 'en-GB'
}
<details>
<summary>英文:</summary>
I am trying to set Google OAuth 2.0 via Passport. I am developping a node.js using express.
Node.js : v18.12.1
When the user hasn't been created yet, I try to create it based on the info provided by Google.
However, the email is missing for some reason.
Scope I am using on OAuth 2.0 :
[![enter image description here][1]][1]
Code extract of the problem :
passport.use(new googleAuth.Strategy({
clientID: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
callbackURL: "http://localhost:3000/auth/google/secrets",
scope: ["email","profile"]
},
(accessToken: string, refreshToken: string, profile: googleAuth.Profile, cb: VerifyCallback) => {
User.findOne({googleId: profile.id}, (err: CallbackError, user: PassportLocalModel<IUser>) => {
if(err){
return cb(err);
}else if(user){
return cb(err, user);
}else{
const user = new User({
email: profile.emails![0].value,
googleId: profile.id,
});
user.save((err: CallbackError) => {
if(err){
console.log(err);
cb(err);
}
})
}
})
}
));
Profile.emails is undefined as well as _json.email (cf : https://developers.google.com/identity/openid-connect/openid-connect#an-id-tokens-payload)
Any idea why ?
Don't hesitate to ask if more info needed.
Thank you
EDIT :
------
Content of the _json (real content hidden) :
_json: {
sub: <somestring>,
name: <some name>,
given_name: <some name>,
family_name: <some name>,
picture: <some url>,
locale: 'en-GB'
}
[1]: https://i.stack.imgur.com/omjUB.png
</details>
# 答案1
**得分**: 0
我找到了解决我的问题的方法。
原来是在身份验证期间覆盖了范围选项。
通过简单地移除该选项,问题已解决。
## 解决方案 ##
```javascript
passport.use(new googleAuth.Strategy({
clientID: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
callbackURL: "http://localhost:3000/auth/google/secrets",
scope: ["profile", "email"]
},
(accessToken: string, refreshToken: string, profile: googleAuth.Profile, cb: VerifyCallback) => {
User.findOne({ googleId: profile.id }, (err: CallbackError, user: PassportLocalModel<IUser>) => {
if (err) {
return cb(err);
} else if (user) {
return cb(err, user);
} else {
const user = new User({
email: profile.emails![0].value,
googleId: profile.id,
});
user.save((err: CallbackError) => {
if (err) {
console.log(err);
cb(err);
}
});
}
})
}
));
app.get("/auth/google",
passport.authenticate("google")
);
英文:
I found the solution to my problem.
Turn out I was overriding the scope options during authentication.
app.get("/auth/google",
passport.authenticate("google", {scope: ["profile"]})
);
By simply removing the option, the problem is fixed.
app.get("/auth/google",
passport.authenticate("google")
);
Solution
passport.use(new googleAuth.Strategy({
clientID: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
callbackURL: "http://localhost:3000/auth/google/secrets",
scope: ["profile", "email"]
},
(accessToken: string, refreshToken: string, profile: googleAuth.Profile, cb: VerifyCallback) => {
User.findOne({googleId: profile.id}, (err: CallbackError, user: PassportLocalModel<IUser>) => {
if(err){
return cb(err);
}else if(user){
return cb(err, user);
}else{
const user = new User({
email: profile.emails![0].value,
googleId: profile.id,
});
user.save((err: CallbackError) => {
if(err){
console.log(err);
cb(err);
}
})
}
})
}
));
app.get("/auth/google",
passport.authenticate("google")
);
答案2
得分: 0
你还可以在Google策略上移除选项,并像这样在身份验证路由中使用:
passport.use(new googleAuth.Strategy({
clientID: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
callbackURL: "http://localhost:3000/auth/google/secrets",
},
(accessToken: string, refreshToken: string, profile: googleAuth.Profile, cb: VerifyCallback) => {
//...
}
));
app.get("/auth/google",
passport.authenticate("google", {scope: ["email", "profile"]})
);
如你所见,你可以在他们的文档中查看更多信息:https://www.passportjs.org/packages/passport-google-oauth20/
英文:
You could also remove the option on the google strategy and use on your auth route like this
passport.use(new googleAuth.Strategy({
clientID: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
callbackURL: "http://localhost:3000/auth/google/secrets",
},
(accessToken: string, refreshToken: string, profile: googleAuth.Profile, cb: VerifyCallback) => {
//...
}
));
app.get("/auth/google",
passport.authenticate("google", {scope: ["email", "profile"]})
);
As you can see at their documentation: https://www.passportjs.org/packages/passport-google-oauth20/
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论