diff --git a/Iceshrimp.Backend/Controllers/Mastodon/AuthController.cs b/Iceshrimp.Backend/Controllers/Mastodon/AuthController.cs index 4b2d6d9c..0906d2b5 100644 --- a/Iceshrimp.Backend/Controllers/Mastodon/AuthController.cs +++ b/Iceshrimp.Backend/Controllers/Mastodon/AuthController.cs @@ -87,9 +87,34 @@ public class AuthController(DatabaseContext db, MetaService meta) : ControllerBa [ProducesErrors(HttpStatusCode.BadRequest)] public async Task GetOauthToken([FromHybrid] OauthTokenRequest request) { - //TODO: app-level access (grant_type = "client_credentials") + if (request.GrantType == "client_credentials") + { + // @formatter:off + var app = await db.OauthApps.FirstOrDefaultAsync(p => p.ClientId == request.ClientId && + p.ClientSecret == request.ClientSecret) ?? + throw GracefulException.Unauthorized("Client authentication failed due to unknown client, no client authentication included, or unsupported authentication method."); + // @formatter:on + + var invalidAppScope = MastodonOauthHelpers.ExpandScopes(request.Scopes ?? []) + .Except(MastodonOauthHelpers.ExpandScopes(app.Scopes)) + .Any(); + if (invalidAppScope) + throw GracefulException.BadRequest("The requested scope is invalid, unknown, or malformed."); + + app.Token ??= CryptographyHelpers.GenerateRandomString(32); + await db.SaveChangesAsync(); + + return new OauthTokenResponse + { + CreatedAt = app.CreatedAt, + Scopes = request.Scopes ?? app.Scopes, + AccessToken = app.Token + }; + } + if (request.GrantType != "authorization_code") - throw GracefulException.BadRequest($"Invalid grant_type, only authorization_code is supported."); + throw GracefulException.BadRequest("Invalid grant_type"); + var token = await db.OauthTokens.FirstOrDefaultAsync(p => p.Code == request.Code && p.App.ClientId == request.ClientId && p.App.ClientSecret == request.ClientSecret); diff --git a/Iceshrimp.Backend/Core/Database/Tables/OauthApp.cs b/Iceshrimp.Backend/Core/Database/Tables/OauthApp.cs index c4007112..4852380f 100644 --- a/Iceshrimp.Backend/Core/Database/Tables/OauthApp.cs +++ b/Iceshrimp.Backend/Core/Database/Tables/OauthApp.cs @@ -61,4 +61,10 @@ public class OauthApp [InverseProperty(nameof(OauthToken.App))] public virtual ICollection OauthTokens { get; set; } = new List(); + + /// + /// The app token, returned by /oauth/token when grant_type client_credentials is requested + /// + [Column("appToken")] [StringLength(64)] + public string? Token; } \ No newline at end of file