add basic suppport for client_credentials oauth grant
This commit is contained in:
parent
049f4a56de
commit
8995213d26
20 changed files with 627 additions and 58 deletions
45
Foxchat.Identity/Controllers/Oauth/AppsController.cs
Normal file
45
Foxchat.Identity/Controllers/Oauth/AppsController.cs
Normal file
|
@ -0,0 +1,45 @@
|
|||
using Foxchat.Core;
|
||||
using Foxchat.Core.Models.Http;
|
||||
using Foxchat.Identity.Authorization;
|
||||
using Foxchat.Identity.Database;
|
||||
using Foxchat.Identity.Database.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Foxchat.Identity.Controllers.Oauth;
|
||||
|
||||
[ApiController]
|
||||
[Authenticate]
|
||||
[Route("/_fox/ident/oauth/apps")]
|
||||
public class AppsController(ILogger logger, IdentityContext db) : ControllerBase
|
||||
{
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> CreateApplication([FromBody] Apps.CreateRequest req)
|
||||
{
|
||||
var app = Application.Create(req.Name, req.Scopes, req.RedirectUris);
|
||||
await db.AddAsync(app);
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
logger.Information("Created new application {Name} with ID {Id} and client ID {ClientId}", app.Name, app.Id, app.ClientId);
|
||||
|
||||
return Ok(new Apps.CreateResponse(
|
||||
app.Id, app.ClientId, app.ClientSecret, app.Name, app.Scopes, app.RedirectUris
|
||||
));
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public IActionResult GetSelfApp([FromQuery(Name = "with_secret")] bool withSecret)
|
||||
{
|
||||
var token = HttpContext.GetToken();
|
||||
if (token is not { Account: null }) throw new ApiError.Forbidden("This endpoint requires a client token.");
|
||||
var app = token.Application;
|
||||
|
||||
return Ok(new Apps.GetSelfResponse(
|
||||
app.Id,
|
||||
app.ClientId,
|
||||
withSecret ? app.ClientSecret : null,
|
||||
app.Name,
|
||||
app.Scopes,
|
||||
app.RedirectUris
|
||||
));
|
||||
}
|
||||
}
|
73
Foxchat.Identity/Controllers/Oauth/TokenController.cs
Normal file
73
Foxchat.Identity/Controllers/Oauth/TokenController.cs
Normal file
|
@ -0,0 +1,73 @@
|
|||
using Foxchat.Core;
|
||||
using Foxchat.Identity.Database;
|
||||
using Foxchat.Identity.Database.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using NodaTime;
|
||||
|
||||
namespace Foxchat.Identity.Controllers.Oauth;
|
||||
|
||||
[ApiController]
|
||||
[Route("/_fox/ident/oauth/token")]
|
||||
public class TokenController(ILogger logger, IdentityContext db, IClock clock) : ControllerBase
|
||||
{
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> PostToken([FromBody] PostTokenRequest req)
|
||||
{
|
||||
var app = await db.GetApplicationAsync(req.ClientId, req.ClientSecret);
|
||||
|
||||
var scopes = req.Scope.Split(' ');
|
||||
if (app.Scopes.Except(scopes).Any())
|
||||
{
|
||||
throw new ApiError.BadRequest("Invalid or unauthorized scopes");
|
||||
}
|
||||
|
||||
switch (req.GrantType)
|
||||
{
|
||||
case "client_credentials":
|
||||
return await HandleClientCredentialsAsync(app, scopes);
|
||||
case "authorization_code":
|
||||
break;
|
||||
default:
|
||||
throw new ApiError.BadRequest("Unknown grant_type");
|
||||
}
|
||||
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private async Task<IActionResult> HandleClientCredentialsAsync(Application app, string[] scopes)
|
||||
{
|
||||
// TODO: make this configurable
|
||||
var expiry = clock.GetCurrentInstant() + Duration.FromDays(365);
|
||||
var (token, hash) = Token.Generate();
|
||||
var tokenObj = new Token
|
||||
{
|
||||
Hash = hash,
|
||||
Scopes = scopes,
|
||||
Expires = expiry,
|
||||
ApplicationId = app.Id
|
||||
};
|
||||
|
||||
await db.AddAsync(tokenObj);
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
logger.Debug("Created token with scopes {Scopes} for application {ApplicationId}", scopes, app.Id);
|
||||
|
||||
return Ok(new PostTokenResponse(token, scopes, expiry));
|
||||
}
|
||||
|
||||
public record PostTokenRequest(
|
||||
string GrantType,
|
||||
string ClientId,
|
||||
string ClientSecret,
|
||||
string Scope,
|
||||
// Optional parameters
|
||||
string? Code,
|
||||
string? RedirectUri
|
||||
);
|
||||
|
||||
public record PostTokenResponse(
|
||||
string Token,
|
||||
string[] Scopes,
|
||||
Instant Expires
|
||||
);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue