Skip to content

Commit 615a2b6

Browse files
adding token refresh
1 parent 5565521 commit 615a2b6

8 files changed

Lines changed: 663 additions & 211 deletions

File tree

ECommerce.AdminUI/Services/AuthService.cs

Lines changed: 86 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,22 @@ public AuthService(IHttpClientFactory httpClientFactory, ILogger<AuthService> lo
2727
Encoding.UTF8,
2828
"application/json");
2929

30-
_logger.LogInformation("Generating token for user {UserName}, request body: {RequestBody}",
30+
_logger.LogInformation("Generating token for user {UserName}, request body: {RequestBody}",
3131
userName, JsonSerializer.Serialize(request));
32-
32+
3333
var response = await _httpClient.PostAsync("/modulith/admin/generateToken", content);
34-
34+
3535
// Read the raw response for debugging
3636
var tokenString = await response.Content.ReadAsStringAsync();
37-
_logger.LogInformation("Response status: {Status}, Content: {Content}",
37+
_logger.LogInformation("Response status: {Status}, Content: {Content}",
3838
response.StatusCode, tokenString);
39-
39+
4040
if (!response.IsSuccessStatusCode)
4141
{
4242
_logger.LogError("Token generation failed with status code {StatusCode}", response.StatusCode);
4343
return null;
4444
}
45-
45+
4646
// The response is plain text containing the token, not JSON
4747
return !string.IsNullOrWhiteSpace(tokenString) ? tokenString.Trim() : null;
4848
}
@@ -53,6 +53,86 @@ public AuthService(IHttpClientFactory httpClientFactory, ILogger<AuthService> lo
5353
}
5454
}
5555

56+
public async Task<string?> RefreshTokenAsync(string token)
57+
{
58+
try
59+
{
60+
_logger.LogDebug("Attempting to refresh token");
61+
62+
var request = new HttpRequestMessage(HttpMethod.Post, "/modulith/admin/refreshToken");
63+
request.Headers.Add("Authorization", $"Bearer {token}");
64+
65+
var response = await _httpClient.SendAsync(request);
66+
67+
if (!response.IsSuccessStatusCode)
68+
{
69+
_logger.LogWarning("Token refresh failed with status code {StatusCode}", response.StatusCode);
70+
return null;
71+
}
72+
73+
var newToken = await response.Content.ReadAsStringAsync();
74+
_logger.LogInformation("Token refreshed successfully");
75+
return !string.IsNullOrWhiteSpace(newToken) ? newToken.Trim() : null;
76+
}
77+
catch (Exception ex)
78+
{
79+
_logger.LogError(ex, "Error refreshing token");
80+
return null;
81+
}
82+
}
83+
84+
// Helper method to execute authenticated requests with automatic refresh
85+
public async Task<(bool Success, HttpResponseMessage? Response)> ExecuteWithTokenRefreshAsync(
86+
Func<string, Task<HttpResponseMessage>> apiCall,
87+
string token,
88+
string username,
89+
HttpContext httpContext)
90+
{
91+
try
92+
{
93+
// First attempt with current token
94+
var response = await apiCall(token);
95+
96+
// If successful, return the response
97+
if (response.IsSuccessStatusCode)
98+
{
99+
return (true, response);
100+
}
101+
102+
// If we get a 401 Unauthorized, try refreshing the token
103+
if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
104+
{
105+
_logger.LogInformation("Received 401 Unauthorized, attempting to refresh token");
106+
107+
// Try to refresh the token
108+
var newToken = await RefreshTokenAsync(token);
109+
110+
if (!string.IsNullOrEmpty(newToken))
111+
{
112+
// Update token in session
113+
httpContext.Session.SetString("AuthToken", newToken);
114+
115+
// Retry the API call with the new token
116+
var retryResponse = await apiCall(newToken);
117+
return (retryResponse.IsSuccessStatusCode, retryResponse);
118+
}
119+
120+
// If refresh fails, clear the token and return false
121+
_logger.LogWarning("Token refresh failed, user needs to re-authenticate");
122+
httpContext.Session.Remove("AuthToken");
123+
return (false, null);
124+
}
125+
126+
// For other error responses, just return as is
127+
return (false, response);
128+
}
129+
catch (Exception ex)
130+
{
131+
_logger.LogError(ex, "Error executing authenticated request");
132+
return (false, null);
133+
}
134+
}
135+
56136
public class TokenRequest
57137
{
58138
public string UserName { get; set; } = string.Empty;
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using Microsoft.AspNetCore.Http;
2+
3+
namespace ECommerce.AdminUI.Services
4+
{
5+
public abstract class BaseService
6+
{
7+
protected readonly IHttpContextAccessor HttpContextAccessor;
8+
protected readonly AuthService AuthService;
9+
protected readonly ILogger Logger;
10+
11+
protected BaseService(
12+
IHttpContextAccessor httpContextAccessor,
13+
AuthService authService,
14+
ILogger logger)
15+
{
16+
HttpContextAccessor = httpContextAccessor;
17+
AuthService = authService;
18+
Logger = logger;
19+
}
20+
21+
protected string? GetTokenFromSession()
22+
{
23+
return HttpContextAccessor.HttpContext?.Session.GetString("AuthToken");
24+
}
25+
26+
protected string? GetUsernameFromSession()
27+
{
28+
return HttpContextAccessor.HttpContext?.Session.GetString("Username");
29+
}
30+
31+
protected void AddAuthorizationHeader(HttpClient httpClient, string token)
32+
{
33+
if (!string.IsNullOrEmpty(token))
34+
{
35+
httpClient.DefaultRequestHeaders.Remove("Authorization");
36+
httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {token}");
37+
}
38+
}
39+
}
40+
}

0 commit comments

Comments
 (0)