I want to create HealthChecks portal via HealthChecksUI but with limited access with authorization.
Also I using Blazor to accomplish authorization dialog creation and receiving access token.
So I configuring HealthChecksUI:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
//...
app.UseEndpoints(endpointsBuilder =>
{
//...
endpointsBuilder.MapHealthChecksUI(setup =>
{
setup.UIPath = "/portal";
setup.ApiPath = "/portal/api";
setup.WebhookPath = "/portal/webhooks";
setup.ResourcesPath = "/portal/resources";
}).RequireAuthorization(); // This means access to '/portal' route will be limited by authorization.
//...
}
//...
}
I using bearer token in HTTP Authorization header for authorization while performing any request.
Next let's check authorization work:
GET request from POSTMAN with valid bearer token to '/portal' route passing successfully. Also, if I change token then I recieve 401 Unauthorized error. So it's seems authorization system working correctly.
Next step will be using authorization dialog to perform token receiving and redirecting to portal page.
Code below it's just a simple authorize function using in .razor page
private async Task SubmitAsync()
{
var (authorizationSuccessful, accessToken) = await authorizationService.AuthorizeAsync(authorizationData).ConfigureAwait(false);
if (authorizationSuccessful)
{
navigationManager.NavigateTo("/portal", true);
}
else
{
throw new UnauthorizedAccessException("Incorrect login or password");
}
}
So problem is:
When authorization passing (authorizationSuccessful is true) and navigation performing, I get to '/portal' page without any authorization data, so I get 401 Unauthorized error.
The question is:
How can I pass received bearer token (accessToken) through NavigateTo method in Authorization HTTP Header to accomplish authorized access to '/portal' page? Is it even possible?
Unfortunately, it's not possible to accomplish this task that way.
According to tries to do something like this using JS only (this and this), it can't be done with plain JS.
So we have just few options here:
Share authorization token through cookies
Cookies are browser-based shared storage, so check access token from here possible right after navigation.
Send authorization token through query
NavigateTo method can be used with query parameters like this:
navigationManager.NavigateTo($"/portal?token={accessToken}", true);
So we can check access token from query parameters directly.
Related
I have a .NET6 ASP.NET Core application that implements a gRPC service as a server.
Authentication is done using Bearer tokens (JWT). After successful authentication+authorization, a server method is invoked to deal with a request, like so:
[Authorize("MyPolicy", AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public override Task<MyResp> MyCall(MyReq request, ServerCallContext context)
{
// ok, I come here
}
Now I need to access one of the claim values that I can expect to be in the token. And I can access the token and find the value I need like so:
var s = context.RequestHeaders.Single(m => m.Key == "authorization").Value;
if (s.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
s = s.Remove(0, 7);
var t = new JwtSecurityTokenHandler().ReadJwtToken(s.Trim());
// now I can look into t.Claims
Fine.
But is there a better way? Before my handler becomes activated, something in the middleware must have inspected that token anyway. Is the collection of claims already available somewhere? I would expect it to be in the ServerCallContext, but I can't find it.
For a project, I have a C# asp.net core server and an Angular web client application. I was following the SignalR documentation on bearer tokens. It states that in order to give the authentication token, you can pass it as follows (copy-paste of the documentation).
let connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub", {
accessTokenFactory: () => {
// Get and return the access token.
// This function can return a JavaScript Promise if asynchronous
// logic is required to retrieve the access token.
}
})
.build();
But now, I would like to extract this specific token on my C# server. The problem is, I can't find it anywhere. only the Context of type HubCallerContext is provided when a user connects in the method public override async Task OnConnectedAsync() or when a user invokes a method himself. But this Contextdoes not supply the given authentication token. How could I extract this?
As far as I know, if you want to get the token in the hub method, you could refer to below codes to get it.
var accessToken = Context.GetHttpContext().Request.Query["access_token"];
I'm using Nancy.Authentication.Stateless 1.4.1 and need to know what is the recommended way of issuing a redirect to a login page whenever the user is not authorized.
Currently, the authentication works in that it returns a 401 to the client. I want to be able to intercept the 401 (server side) and instead send the user to the login page.
I can see that this is possible with Forms Authentication as stated here (https://github.com/NancyFx/Nancy/wiki/Forms-authentication)
Snippet (for Forms Authentication)
var formsAuthConfiguration =
new FormsAuthenticationConfiguration()
{
RedirectUrl = "~/login",
UserMapper = container.Resolve<IUserMapper>(),
};
Just a bit stumped on how to do this when using StatelessAuthenticationConfiguration
You can manually implement this in a custom handler for the After pipeline (see The Application Before After and OnError pipelines) or a module's After hook (see The before and after hooks) that will replace the response with a redirect response it it is unauthorized.
To enable it at the application level, you can use something like this:
pipelines.AfterRequest.AddItemToEndOfPipeline(RedirectUnauthorizedRequests);
where the RedirectUnauthorizedRequests method could look something like this:
private static Action<NancyContext> RedirectUnauthorizedRequests()
{
return context =>
{
if (context.Response.StatusCode == HttpStatusCode.Unauthorized)
{
context.Response = context.GetRedirect("/login");
}
};
}
I have a Web API project which implements authentication via OAuthAuthorizationServerProvider. I've subclassed the provider and have implemented methods as necessary to implement my own authentication system.
I also have figured out how to override the return value provided for unauthenticated requests (you have to subclass the AuthorizeAttribute class and then use your custom attribute instead of Authorize on endpoints you intend to secure).
I can also override the TokenResponse method in my OAuth auth server provider in order to alter the response containing the token.
Now what I'm trying to do is to override the response provided by the token endpoint when a user provides incorrect credentials to the token endpoint. Right now, I simply get this:
{"error":"invalid_grant","error_description":"The user name or password is incorrect."}
I know where this text is coming from - in my GrantResourceOwnerCredentials method I do the following if a request is not authenticated:
if (!isValidUser)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
Instead though, I want to be able to fully manipulate the Response object that is returned when the user provides incorrect credentials.
As an example, I might want to set the return to look like this:
{"error":401,"timestamp":1234567890,"message":"Those credentials are wrong. Try again."}
Is there a way to override the response that the server provides upon failed authentication?
You cannot change this behaviour. You only can change the fields in context.SetError() method.
In this case the response, including the status code, is composed in SendErrorAsJsonAsync() private method, inside OAuthAuthorizationServerHandler internal class, in Microsoft.Owin.Security.OAuth dll.
You can revise the code in OAuthAuthorizationServerHandler class for more details.
Try the below code, refer here
public class CustomAccessTokenProvider : AuthenticationTokenProvider
{
public override void Receive(AuthenticationTokenReceiveContext context)
{
context.DeserializeTicket(context.Token);
var expired = context.Ticket.Properties.ExpiresUtc < DateTime.UtcNow;
if (expired)
{
//If current token is expired, set a custom response header
context.Response.Headers.Add("X-AccessTokenExpired", new string[] { "1" });
}
base.Receive(context);
}
}
Register it when setting up OWIN OAuth:
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
{
AccessTokenProvider = new CustomAccessTokenProvider()
});
The Problem:
MobileServiceClient.LoginAsync never exits the login dialog - even after the access token gets returned.
The Environment:
Backend: Windows Azure Mobile Service .Net/C#
Frontend: Windows 8.1 Universal Store App. .Net/C#
The Details:
In my app, the following code fails to return from the dialog that is brought up on the second line:
var client = new MobileServiceClient("https://hana.azure-mobile.net", applicationKey);
var result = await client.LoginAsync("SmartThings");
Speculation:
I suspect that the code in my custom AuthenticationHandler for handling a challenge, is mostly to blame. The RedirectUri in the AuthenticationProperties for my override of ApplyResponseChallengeAsync, is always null - so it sets the redirect uri to the request uri.
The code looks like the following:
var redirectUri = Request.FromPath(Options.CallbackPath);
var properties = challenge.Properties;
if (String.IsNullOrEmpty(properties.RedirectUri))
{
properties.RedirectUri = Request.Uri.AbsoluteUri;
}
// OAuth2 10.12 CSRF
GenerateCorrelationId(properties);
var requestUrl = FormAuthorizeRequest(properties, redirectUri);
Response.Redirect(requestUrl);
Attempts at resolution
Use WebAuthenticationBroker instead of MobileServiceClient and expliticly provide the callback uri.
Remove reassignment to redirect uri.
Switch redirect and request uris.
Throw salt over my shoulder.
Use Test frontend on service to navigate and test login.
Use HttpClient and explicitly construct the request with the following parameter keys: "redirect_uri", "redirect_url", "redirectUrl", "redirectUri".
Bleed a goat
Change the CallbackPath value of the AuthenticationOptions to "/signin-SmartThings".
Await Ragnarok
Additional Details
I had to create a custom LoginProvider and OWIN Middleware to register my custom AuthenticationHandler into the owin pipeline. This appears to have been setup correctly, but the implementation of my AuthenticationHandler may be erroneous. I will gladly provide additional details on request if it will help expedite this issue.
Updates:
The response from SmartThings gives an error with "redirect_mismatch" in the body when trying to login from a WebAuthenticationBroker with a provided callback uri.
However, when navigating through the browser, the redirect uri gets processed as "https://hana.azure-mobile.net/signin-SmartThings?code=somemassivecode"
This confuses me a bit because I was expecting to see an access token, rather than an auth token, as the redirect uri.