
做运维这些年git clone报Authentication failed是我见过最容易被低估的报错。很多人第一反应就是“密码错了”于是反复输入账号密码折腾半天还是在原地打转。尤其是公司仓库接入SSO 单点登录之后这个问题会变得更迷惑浏览器里明明已经用Authentik登录成功了一回到命令行git clone还是提示认证失败。今天这篇就把这条链路从头捋一遍讲清楚认证失败背后的机制给出用 SSO 配合 Authentik 登录 Git 仓库的完整落地方式也把我在实际环境中踩过的坑一并列出来。适合正在搭建或维护 Git 仓库、被各种 401/403 折磨的运维和开发者。1. 先搞清楚 Authentication failed 到底是谁在拒绝你1.1 报错出现的两种典型场景这类报错通常有两种出现方式。第一种是命令刚发出去终端直接回一句fatal: Authentication failed for https://git.example.com/team/repo.git/第二种是 Git 先弹出用户名和密码输入框你输入完以后它慢悠悠地拒绝你。无论是哪种本质都是 HTTP 层面的401 Unauthorized——仓库服务器收到了你的请求但认为你没有通过身份验证。这里有个很容易被忽略的细节Authentication failed不等于密码错误。密码错误只是其中一个触发原因token 失效、用户名格式不对、账号被禁用、仓库服务配置了额外的访问控制甚至是你本地 Git 装了旧版凭据缓存都会让你看到同一句报错。所以排查的第一步永远是确认“到底是哪一端拒绝了我”。最简单的验证办法是打开浏览器的无痕模式直接访问仓库地址。如果浏览器能正常打开并能看到登录页说明仓库服务本身是活的如果网页登录也报错那问题根本不在 Git 客户端而在服务端或账号状态。1.2 HTTP Basic Auth 的认证链路Git 在使用 HTTP/HTTPS 协议拉取代码时默认走的是HTTP Basic Authentication。这种认证方式非常朴素客户端把“用户名:密码”拼在一起做一次 Base64 编码然后塞进请求头里的Authorization字段。Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ服务器收到后会解码这段内容拿去和自己的账号体系比对。比对通过就返回代码数据比对不通过就返回 401同时带上一个WWW-Authenticate头告诉客户端“你需要重新认证”。Git 看到 401 以后就会把那句经典的Authentication failed扔到你脸上。注意Basic Auth 里的 Base64 只是编码不是加密。只要有人抓包就能轻易还原出明文密码。这也是为什么很多企业仓库不愿意让你把真正的账密直接喂给 Git更不愿意让你把密码长期存在本地配置文件里。1.3 为什么普通密码在 SSO 仓库上行不通当你给 Git 仓库接上SSO 单点登录之后事情就变了。接入 Authentik 这类身份提供者后仓库服务器本身不再保存你的登录密码它只负责把浏览器里的登录请求“转发”给 AuthentikAuthentik 验证通过后再告诉仓库服务器“这个人可信”。这带来一个直观结果**网页登录密码和 Git 命令行登录密码从一开始就不是同一个东西。**你在浏览器里能登录是因为 Authentik 给你发了一个会话凭证浏览器靠这个凭证访问仓库网页但你的git clone命令并没有浏览器那个会话它只会笨笨地拿着你输入的账密去做 Basic Auth而仓库服务器手里根本没有这份账密自然只能回你 401。打个比方仓库大楼有两道门。第一道门是 Authentik 前台你刷脸进去前台给你一张临时访客牌第二道门是 Git 代码库的门禁它不认你的脸只认访客牌上的二维码。SSO 解决的是第一道门而git clone需要的是第二道门的凭证。如果你拿着一张脸就去刷第二道门被拒之门外就完全不意外了。2. 用 Authentik 做仓库 SSO 登录的设计思路2.1 Authentik 在认证链里的角色Authentik 是一个开源的身份提供者可以用来做统一登录、用户管理、权限分组、多因素认证。它支持 OIDC、LDAP、SAML 这些主流协议既可以对接企业已有的 LDAP/AD 目录也可以自己维护一套用户库。在 Git 仓库的 SSO 链路里Authentik 扮演的是“身份源头”的角色。Gitea、GitLab、Forgejo 这些仓库系统并不直接验证密码而是把自己配置成 Authentik 的一个客户端。用户访问仓库网页时仓库系统把浏览器重定向到 Authentik 的登录页用户输完密码Authentik 又把人带回仓库系统同时通过安全令牌告诉仓库系统“这个用户已经通过了我的认证这是他的身份信息。”这个流程对使用者来说很舒服一个账号走天下不用每个系统都记一套密码。但对 Git 命令行工具来说问题就在于它不在浏览器里没法跟着走“重定向到登录页再跳回来”这套流程所以必须拿出另一个凭证来通过门禁。2.2 Git 生态怎么对接 SSOOAuth2/OIDC 与 personal access tokenGit 生态对接 SSO 的常见做法不是让 Git 直接实现 OIDC 登录而是让仓库系统支持OAuth2 / OIDC 登录登录成功后用户再手动生成一个Personal Access Token个人访问令牌这个 token 就是第二道门的二维码。完整流程大致是这样管理员在 Authentik 里创建 OIDC Provider拿到客户端 ID 和客户端密钥。在 Gitea/GitLab 里配置这个 Provider填上回调地址和自动发现 URL。用户访问仓库网页选择“使用 Authentik 登录”浏览器完成 SSO 认证。用户在仓库系统的个人设置里生成一个 Personal Access Token。用户在命令行执行git clone用户名填仓库账号密码填这个 token。为什么不能把 Authentik 的登录密码直接给 Git 用原因有三点一是 Basic Auth 会把密码以明文方式发到服务器风险太高二是很多企业启用了多因素认证用户密码根本就不是一个可以长期重复使用的静态凭证三是 token 可以精确控制权限范围可以设置过期时间出了问题还能单独吊销不会影响账号主体。这就像你不可能把家里的钥匙随便交给快递员但你可以给他一张限时、限定区域的临时门禁卡。2.3 推荐方案让 Git 走浏览器授权而不是硬记密码实际操作中我推荐大家采用“网页 SSO 登录 Personal Access Token 本地凭据管理器”这套组合。它不要求你手工保存任何密码第一次 clone 时输入一次 token之后 Git 会通过凭据管理器自动完成认证。如果你用的是较新的环境还可以考虑OAuth 2.0 Device Authorization Grant设备授权流程。这个流程允许客户端在无浏览器环境下让用户在一台有浏览器的设备上完成授权然后客户端自动拿到令牌。部分 Git 凭据管理器内置了这种能力比如 GitHub CLI、某些 Git 分发版本里的 credential manager。不过这套东西对服务端和客户端都有要求不是所有 Gitea/GitLab 版本都开箱即用所以我的建议仍是先把最朴素的“token 方案”跑通再考虑要不要上更复杂的设备授权。下面用一个表格简单对比几种方式认证方式是否需要浏览器适合场景风险点网页 SSO 登录是平时在网页端浏览代码、合并请求无法直接用于命令行Personal Access Token否命令行 clone、push、CI/CD 机器账号token 泄露会导致仓库被未授权访问设备授权流程是但不强制在终端环境无浏览器服务器上运行 Git配置复杂依赖服务端支持SSH 密钥否开发者日常代码操作需要单独管理密钥和多因素认证联动弱3. 实操从配置 Authentik 到 git clone 一次通过3.1 在 Authentik 里创建 Provider 和 Application第一步在 Authentik 管理后台左侧菜单里找到Providers点击右上角的新建。选择OAuth2/OIDC Provider。需要填的关键字段如下Name起一个能认出来的名字比如Gitea OIDC。Client Type选Confidential因为仓库系统要用客户端密钥去换 token。Client ID 和 Client Secret可以自己填也可以点击生成按钮让 Authentik 随机生成。务必把这个 secret 保存好后面配置仓库系统时会用到。Redirect URIs / 回调地址填仓库系统提供的回调地址。比如 Gitea 通常长这样https://git.example.com/user/oauth2/authentik/callback具体路径需要看仓库系统文档。Signing Key选一个已有的 RSA 签名密钥或者新建一个。这个密钥用于签发 ID Token。Provider 创建好以后再去Applications里新建一个应用给它起个名字比如Git Repo SSO。然后在应用的Provider标签页里把刚创建的那个 Provider 关联进去。一个容易忽略的小细节如果你希望只有指定用户组才能通过 SSO 登录仓库可以在 Provider 的授权规则里限制用户或组。不设限制的话Authentik 里所有能登录的用户都能访问仓库系统这在生产环境里很危险。3.2 在 Gitea/GitLab 里启用 OIDC 登录仓库系统的配置是第二个关键步骤。以 Gitea 为例进入站点管理后台找到“认证源”或“Authentication Sources”点击添加认证源选择OAuth2或OpenID Connect。关键配置项认证名称给这个源起个名方便用户登录页显示。Provider选OpenID Connect。客户端 IDClient ID填 Authentik 里生成的那个。客户端密钥Client Secret填 Authentik 里生成的 secret。OpenID Connect 自动发现 URL填 Authentik 的 OIDC 配置地址通常格式是https://authentik.example.com/application/o/gitea-oidc/.well-known/openid-configuration如果填对了Gitea 会自动拉取 Authentik 提供的授权地址、token 地址、用户信息地址不需要手工逐项填写。这能避免很多因为地址写错而导致的“能跳转但登录失败”问题。保存之后回到登录页你会看到多了一个“使用 Authentik 登录”的按钮。点它如果浏览器能成功跳转到 Authentik 并再跳回来说明 OIDC 配置已经通了。此时网页端已经可以使用 SSO 登录但命令行还需要 next 步骤。GitLab 的配置思路类似在 Admin Area - Applications 里添加 OIDC 应用回调地址参照 GitLab 的users/auth/authentik/callback路径。不同版本的字段名可能有差异核心就是填对客户端 ID、secret 和发现 URL 三件套。3.3 使用 access token 完成首次 git clone网页端登录已经成功现在要解决命令行登录。打开 Gitea 的用户设置界面找到Applications / 应用在“生成新的令牌”区域填一个名字勾选你需要的权限范围。对于只想拉代码的场景勾选read:repository就够了如果需要推送代码再勾选写权限。生成之后Gitea 会给你显示一段以gitea_开头的字符串。这个字符串只在生成时完整显示一次页面刷新就没了所以最好先复制到临时地方。接下来执行git clone https://git.example.com/team/repo.gitGit 提示输入用户名时填你的仓库用户名提示输入密码时粘贴刚才的 token 并回车。注意千万不要把 token 直接写在 clone 地址里# 危险示例不要这样做 git clone https://username:gitea_tokengit.example.com/team/repo.git这种写法虽然能一次通过但 token 会随命令一起写进 shell 历史文件、终端回放记录甚至可能出现在监控日志里。一旦泄露别人就能拿你的身份操作仓库。安全习惯要养成在前面宁可在命令行手动输入也别图省事。3.4 让 Git 记住凭据credential helper 配置每次 clone 都要手输 token 很麻烦而且 token 通常有有效期没人保证你三个月后还记得住这串东西。解决办法是用 Git 的 credential helper 把凭据缓存到系统级凭据管理器里。Linux 桌面环境可以用git config --global credential.helper libsecretmacOS 自带钥匙串可以配置为git config --global credential.helper osxkeychainWindows 上建议使用 Git Credential Managergit config --global credential.helper manager-core配置完成后第一次 clone 时输入一次 token之后 Git 会把凭据交给系统钥匙串管理。后续 pull、push 都不需要再手动输入而且密码不会以明文躺在~/.gitconfig里。有一点要特别提醒git config --global credential.helper store这个选项虽然配置最简单但它会把凭据以明文形式写入~/.git-credentials。在个人电脑上它勉强能用在服务器或多人共用设备上这就是给自己埋雷。我的建议是能用系统钥匙串就不要用 store实在没有桌面环境的服务器宁可用 SSH 密钥方案。4. 常见问题与排查实录4.1 端口 7890 报错怎么处理很多人在配置完 SSO 后明明 token 没问题却看到下面这个报错git clone failed to connect to 127.0.0.1 port 7890: connection refused这个报错和认证一点关系都没有。它的意思是 Git 尝试连接本机的 7890 端口但那个端口上没有服务在监听。出现这种问题的常见原因是你的 Git 全局配置里残留了指向127.0.0.1:7890的网络转发设置或者当前 shell 环境变量里存在指向这个端口的记录。Git 以为是“先走本地通道再访问远程”但本地通道服务没开连第一个连接都建不起来自然不可能进入认证阶段。排查思路分两步。第一步先看 Git 全局配置里有没有残留项git config --global --list重点看哪些地址指向了127.0.0.1。第二步检查当前环境变量里有没有相关的转发设置env如果在环境变量里看到了指向 7890 的地址可以临时清除后再试。整个排查过程要记住一个原则先让 Git 能够直连仓库服务器再谈认证问题。很多认证报错其实是网络层没走通被误认成密码错误查了半天方向完全跑偏。4.2 每次 clone 都弹登录框配置了 credential helper 之后如果 Git 还是每次都重新问密码大概率是 helper 没真正生效或者本地钥匙串里没有保存成功。先执行git config --global --get credential.helper看看输出是不是你预期的那条配置。如果输出为空说明配置没写进去。另一个常见原因是不同仓库域名走的是不同 helperGit 匹配不到自然每次都重新认证。还有一个容易忽略的问题如果你从https://git.example.comclone但 Gitea 跳转到 Authentik 时用的是https://authentik.example.com这两个域名在凭据管理器里是两条记录。你输入的 token 如果是 Gitea 的它应该挂在git.example.com下如果挂到了authentik.example.com下次访问 Gitea 时依然会提示认证失败。检查一下钥匙串里记录的域名是否正确很多时候比重新输入密码更管用。4.3 token 失效、权限不足与 403Authentication failed是 401但如果 token 权限不足你可能会看到 403 Forbidden。这个区别很值得记下来401 表示“我不知道你是谁”403 表示“我知道你是谁但你不被允许”。权限不足最常见的场景是勾选 token 权限时只选了read:repository但之后试图往仓库推送代码或者用同一个 token 访问另一个需要写权限的仓库结果被拒。解决方法是回到用户设置里生成新的 token按实际需求勾选权限尽量遵循最小权限原则。还有一个隐蔽问题用户通过 Authentik SSO 登录后如果这个账号没有同步进仓库系统里对应的团队或项目组登录可能成功但访问某些私有仓库时依然被 403 拒绝。Gitea 通常会把 OIDC 用户归属到一个自动创建的账号下管理员需要确认该账号是否被加入了正确的团队。Authentik 侧也可以配置组同步让认证通过的用户自动进入仓库系统的指定团队这一步配好之后能省掉很多手动加人的麻烦。4.4 避坑经验清单最后整理一份我这些年摔过的坑做成清单方便直接抄作业。不要在 URL 里直接嵌入 token。命令行历史和监控日志都会记录泄露风险极高。不要混用 SSO 密码和 Git token。网页登录用 SSO 密码命令行只认 token两者不是一个东西。token 要设置合理过期时间。长期 token 虽然方便但一旦流出后果比想象中严重有条件的可以用短期 token 定期轮换机制。Client Secret 不要提交到代码仓库。Authentik 里的 Provider 配置如果写进配置管理文件一定要用单独的密钥管理服务保存不要明文提交。限制 Authentik 的授权范围。Provider 层面配置允许访问的用户组避免整个身份库都能登录你的 Git 仓库。回调地址必须严格匹配。多一个斜杠、少一个路径都会导致“登录成功但跳回失败”排查时先对比两端回调地址是否完全一致。凭据管理器优先于明文存储。store虽然简单但明文存密码的方式在团队环境里会造成严重安全隐患。SSO 退出不会自动吊销 token。用户甚至在 Authentik 里改了密码旧 token 可能依然有效。所以在人员离职或怀疑泄露时要主动吊销相关 token。这块内容看起来零零散散但每一个都是我在实际环境里见过的问题。尤其是“URL 里带 token”和“明文 store”两个坑几乎每隔几个月就能遇到一次。养成“token 一次性使用、凭据进钥匙串、回调地址严格验证”的习惯之后整个 SSO 登录流程会稳定很多。我个人在实际操作中最舒服的流程是网页端走 Authentik SSO 登录命令行用 SSH 密钥而不是 HTTP token。如果你用的仓库系统支持 SSH我更推荐直接走 SSH 方式它能避开 Basic Auth 带来的一系列痛点。不过很多企业内部网络只开放 HTTPS 端口这种情况下“网页 SSO token 系统钥匙串”就是最可靠的折中方案。