➡️【好看的皮囊千篇一律,有趣的鲲志一百六七!】- 欢迎认识我~~ 作者:鲲志说 (公众号、B站同名,视频号:鲲志说996) 科技博主:极星会 星辉大使 全栈研发:java、go、python、ts,前电商、现web3 主理人:COC杭州开发者社区主理人 、周周黑客松杭州主理人、 博客专家:阿里云专家博主;CSDN博客专家、后端领域新星创作者、内容合伙人 AI爱好者:AI电影共创社杭州核心成员、杭州AI工坊共创人、阿里蚂蚁校友会技术AI分会副秘书长
——从 OAuth 认知误区,到 ID Token 校验失败的工程级排错

我在做一个支持 第三方登录 的系统,希望第一步先接入 Google 登录,作为一个标准、规范、文档相对完善的 OAuth2 Provider,用来打通整体账号体系设计。
整体目标很清晰:
但真正开始做之后,我发现: 90% 的坑,不在 OAuth,而在“Token 类型 + 时间校验 + 工程细节”

⚠️ 核心点:后端只认 ID Token,不认 access_token
这是我一开始就确认的结构,而不是边写边改。
id
email
nickname
avatar
created_atid
user_id
provider // google
provider_uid // Google 的 sub
email
created_at否则会引发:
前端使用的是:
npm i @react-oauth/google然后前端同学告诉我:
“我们拿到的是 access_token,没有 credential 字段。”
这一步是 90% 人会踩的坑。

👉 后端登录只能用 id_token,其本质是一个 JWT,专门用来证明「这个用户就是 Google 认证过的某个人」
<GoogleLogin
onSuccess={(res) => {
// res.credential 就是 id_token
fetch('/api/auth/google', {
method: 'POST',
body: JSON.stringify({
id_token: res.credential,
}),
})
}}
/>如果你拿到的是 access_token,说明你用的是 OAuth 授权模式,不是 身份登录模式。
import "google.golang.org/api/idtoken"payload, err := idtoken.Validate(
ctx,
req.IDToken,
googleClientID,
)
if err != nil {
return errors.New("invalid google id token")
}校验成功后能拿到:
email := payload.Claims["email"].(string)
sub := payload.Subject // Google 用户唯一 IDidtoken.Validate 永远失败Google ID Token 内部包含:
nbf // not before
iat // issued at
exp // expiresidtoken.Validate 内部会用:
time.Now().UTC()来做严格校验。
哪怕:
都会直接失败。
我打印了:
log.Println("server utc now:", time.Now().UTC())
log.Println("token iat:", time.Unix(payload.IssuedAt, 0).UTC())发现:
server utc now < token iat直接实锤。
❌ 不推荐跳过校验 ❌ 不推荐自己 parse JWT ❌ 不推荐用 access_token 冒充登录
OAuth ≠ 登录 ID Token 才是身份凭证 时间是安全系统的一部分
Google 登录这套体系本身非常严谨,真正容易出问题的地方是:
但好消息是:
只要把 Google 登录跑通了, 其他第三方登录都会变得异常简单。
至此,我已经把X、Telegram、Google 的基本授权登录等功能都跑通了。 这是一次非常值得的踩坑。