feat(oauth): support the profile scope

A token with only the profile scope can call verify_credentials, as in
Mastodon 4.3. The answer is the public account, so apps can use it to
log users in without seeing their email or settings.
This commit is contained in:
Lain Soykaf 2026-10-26 12:26:07 +04:00
commit 530ae4b339
No known key found for this signature in database
7 changed files with 90 additions and 4 deletions

View file

@ -48,7 +48,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
description: "Test to make sure that the user token works.",
summary: "Verify account credentials",
operationId: "AccountController.verify_credentials",
security: [%{"oAuth" => ["read:accounts"]}],
security: [%{"oAuth" => ["read:accounts"]}, %{"oAuth" => ["profile"]}],
responses: %{
200 => Operation.response("Account", "application/json", Account)
}

View file

@ -24,6 +24,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
alias Pleroma.Web.MastodonAPI.MastodonAPI
alias Pleroma.Web.MastodonAPI.StatusView
alias Pleroma.Web.OAuth.OAuthController
alias Pleroma.Web.OAuth.Token
alias Pleroma.Web.Plugs.OAuthScopesPlug
alias Pleroma.Web.Plugs.RateLimiter
alias Pleroma.Web.Registration
@ -49,8 +50,12 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
plug(
OAuthScopesPlug,
%{scopes: ["read:accounts"]}
when action in [:verify_credentials, :endorsements, :own_endorsements]
%{scopes: ["read:accounts", "profile"]} when action == :verify_credentials
)
plug(
OAuthScopesPlug,
%{scopes: ["read:accounts"]} when action in [:endorsements, :own_endorsements]
)
plug(
@ -161,7 +166,18 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
end
@doc "GET /api/v1/accounts/verify_credentials"
def verify_credentials(%{assigns: %{user: user}} = conn, _) do
def verify_credentials(%{assigns: %{user: user, token: %Token{scopes: scopes}}} = conn, _) do
if OAuthScopesPlug.filter_descendants(["read:accounts"], scopes) == [] do
# The profile scope only identifies the user: show what anyone can see.
render(conn, "show.json", user: user, skip_visibility_check: true)
else
render_own_account(conn, user)
end
end
def verify_credentials(%{assigns: %{user: user}} = conn, _), do: render_own_account(conn, user)
defp render_own_account(conn, user) do
chat_token = Phoenix.Token.sign(conn, "user socket", user.id)
render(conn, "show.json",