如何通过Mastodon API的OAuth获取用户邮箱?
Mastodon OAuth认证无法获取用户邮箱的问题
我正在给一个.NET Core应用添加基于Mastodon API的OAuth认证,调用/api/v1/accounts/verify_credentials端点时,只能拿到"id"和"display_name"字段,拿不到邮箱属性,目前只能用"acct"参数替代。我已经配置了"read:accounts"和"admin:read:accounts"权限范围,想确认有没有能返回当前用户邮箱的Mastodon API端点,查过官方文档没找到相关内容。
相关代码实现:
builder.Services.AddAuthentication() .AddMicrosoftAccount("Microsoft", "Microsoft", microsoftOptions => { microsoftOptions.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; microsoftOptions.ClientId = _appSettings.Authentication.Microsoft.ClientId; microsoftOptions.ClientSecret = _appSettings.Authentication.Microsoft.ClientSecret; }) .AddGoogle("Google", "Google", googleOptions => { googleOptions.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; googleOptions.ClientId = _appSettings.Authentication.Google.ClientId; googleOptions.ClientSecret = _appSettings.Authentication.Google.ClientSecret; }) .AddGitHub("GitHub", "GitHub", githubOptions => { githubOptions.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; githubOptions.ClientId = _appSettings.Authentication.GitHub.ClientId; githubOptions.ClientSecret = _appSettings.Authentication.GitHub.ClientSecret; }) .AddOAuth("Fosstodon", "Fosstodon", fosstodonOptions => { fosstodonOptions.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; fosstodonOptions.ClientId = _appSettings.Authentication.Fosstodon.ClientId; fosstodonOptions.ClientSecret = _appSettings.Authentication.Fosstodon.ClientSecret; fosstodonOptions.CallbackPath = new PathString("/signin-fosstodon"); fosstodonOptions.AuthorizationEndpoint = _appSettings.Authentication.Fosstodon.AuthorizationEndpoint; fosstodonOptions.TokenEndpoint = _appSettings.Authentication.Fosstodon.TokenEndpoint; fosstodonOptions.UserInformationEndpoint = _appSettings.Authentication.Fosstodon.UserInformationEndpoint; fosstodonOptions.SaveTokens = true; fosstodonOptions.Scope.Add("read:accounts"); fosstodonOptions.Scope.Add("admin:read:accounts"); fosstodonOptions.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id"); fosstodonOptions.ClaimActions.MapJsonKey(ClaimTypes.Name, "name"); fosstodonOptions.ClaimActions.MapJsonKey(ClaimTypes.Email, "email"); fosstodonOptions.Events = new OAuthEvents { OnCreatingTicket = async context => { var request = new HttpRequestMessage(HttpMethod.Get, context.Options.UserInformationEndpoint); request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", context.AccessToken); var response = await context.Backchannel.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, context.HttpContext.RequestAborted); response.EnsureSuccessStatusCode(); var user = JObject.Parse(await response.Content.ReadAsStringAsync()); var identifier = user.Value<string>("id")?.Clean(); if (!string.IsNullOrEmpty(identifier)) { context.Identity?.AddClaim(new Claim( ClaimTypes.NameIdentifier, identifier, ClaimValueTypes.String, context.Options.ClaimsIssuer)); } var userName = user.Value<string>("display_name")?.Clean(); if (!string.IsNullOrEmpty(userName)) { context.Identity?.AddClaim(new Claim( ClaimTypes.Name, userName, ClaimValueTypes.String, context.Options.ClaimsIssuer)); } var userEmail = user.Value<string>("acct")?.Clean(); if (!string.IsNullOrEmpty(userEmail)) { context.Identity?.AddClaim(new Claim( ClaimTypes.Email, userEmail, ClaimValueTypes.String, context.Options.ClaimsIssuer)); } } }; });
解答
核心结论
Mastodon的公开API不会返回用户邮箱地址,哪怕请求了read:accounts或admin:read:accounts权限。这是出于用户隐私保护的设计——邮箱属于敏感信息,Mastodon默认不会通过OAuth接口对外暴露。
关键原因
- 隐私优先设计:Mastodon作为去中心化社交平台,用户邮箱仅用于账号验证、密码重置等内部操作,不允许第三方应用通过OAuth获取。
- 权限范围限制:
read:accounts权限仅能获取公开的账号信息(如ID、显示名、用户名acct);admin:read:accounts是服务器管理员专属接口,仅对本地管理员账号有效,且同样不会返回普通用户的邮箱。
替代方案
你目前用acct字段作为邮箱替代是合理的,因为acct格式通常为用户名@实例域名,可以作为用户的唯一标识。如果应用必须获取邮箱,只有两种可行路径:
- 引导用户手动输入并验证邮箱;
- 如果你控制自己的Mastodon服务器,可以修改服务器代码或插件自定义返回邮箱字段,但这不符合标准API规范,无法兼容其他公共实例。
代码优化建议
既然API不会返回email字段,建议移除无效的Claim映射:
// 移除该行,因为Mastodon API不会返回email字段 // fosstodonOptions.ClaimActions.MapJsonKey(ClaimTypes.Email, "email");
内容的提问来源于stack exchange,提问作者Chris Cavell
相关产品推荐
相关产品推荐

