diff --git a/src/Server/Controllers/OAuth.cs b/src/Server/Controllers/OAuth.cs index 7a7d289..34f22bf 100755 --- a/src/Server/Controllers/OAuth.cs +++ b/src/Server/Controllers/OAuth.cs @@ -2,6 +2,8 @@ using Auth.Services.DatabaseService; using System.Web.Http; using Auth.Entities; +using System.Text; +using System.Security.Cryptography; namespace Auth.Controllers { [ApiController] @@ -10,10 +12,28 @@ namespace Auth.Controllers { public OAuthController(DatabaseService db) : base(db) {} + private string GenerateCodeChallenge(string codeVerifier) { + using var sha256 = SHA256.Create(); + var bytes = sha256.ComputeHash(Encoding.ASCII.GetBytes(codeVerifier)); + return Base64UrlEncode(bytes); + } + + private string Base64UrlEncode(byte[] input) { + return Convert.ToBase64String(input) + .TrimEnd('=') + .Replace('+', '-') + .Replace('/', '_'); + } + [HttpGet("/authorize")] public async Task Authorize([FromQuery] AuthorizationRequest request) { try { - + + // Verify login + // create guid + // set guid to account + // save account to database + return NotFound("User is not logged in"); } catch (Exception ex) { Console.WriteLine("Delete Error: " + ex.Message); @@ -21,11 +41,55 @@ namespace Auth.Controllers { } } - [HttpGet("/token")] + [HttpPost("/token")] public async Task Token([FromForm] TokenRequest request) { try { + + // Validate Grant Code + if (request.GrantType != "authorization_code") { + return BadRequest(new { error = "unsupported_grant_type" }); + } + + // Validate Required Parameters + if (string.IsNullOrEmpty(request.Code) || string.IsNullOrEmpty(request.RedirectUri) || string.IsNullOrEmpty(request.CodeVerifier)) { + return BadRequest(new { error = "invalid_request" }); + } + + // Check if LoginToken is expired + var authCode = AuthorizationCodeStore.Get(request.Code); + if (authCode == null || authCode.IsExpired) { + return BadRequest(new { error = "invalid_grant" }); + } + + // Verify redirect_uri matches + if (!string.Equals(authCode.RedirectUri, request.RedirectUri, StringComparison.Ordinal)) { + return BadRequest(new { error = "invalid_grant" }); + } + + // 5. Verify code_verifier (PKCE check) + var expectedChallenge = GenerateCodeChallenge(request.CodeVerifier); + if (authCode.CodeChallenge != expectedChallenge) { + return BadRequest(new { error = "invalid_grant", error_description = "PKCE verification failed" }); + } + + // 6. Optionally verify client_id/client_secret (for confidential clients) + // ... + + // 7. Issue access token (and refresh token if needed) + var accessToken = TokenService.GenerateAccessToken(authCode.UserId, authCode.ClientId, authCode.Scope); + var refreshToken = TokenService.GenerateRefreshToken(authCode.UserId, authCode.ClientId); + + // 8. Invalidate used authorization code (one-time use) + AuthorizationCodeStore.Remove(request.Code); + + // 9. Return token response + return Ok(new { + access_token = accessToken, + token_type = "Bearer", + expires_in = 3600, + refresh_token = refreshToken + }); - return NotFound("User is not logged in"); } catch (Exception ex) { Console.WriteLine("Delete Error: " + ex.Message); return NotFound("An internal server error has occured");