I have a question about Bearer Token on asp.net WebApi. I've been creating WebApi's but just to be consumed by some client(Android,iOS), but now I need to create a Login page in this same project and I don't know how to handle this, since once using a client app, i just make a request to api/token and get the access token, but how to get this from a Web Page? Do I need to use some back-end like NodeJs or AngularJS ?
This is the endpoint :
app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions()
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(300),
AllowInsecureHttp = true
});
Essentially, whatever you use on the client side to get the token (I use Angular and React as they have in built functionality for making http requests), you then need to get the response and store the token in the client. Take a read of this https://stormpath.com/blog/where-to-store-your-jwts-cookies-vs-html5-web-storage. It should give you a bit of insight into client side storage. Again I tend to use cookies as it's built in with a lot of the .net MVC stuff, but you could use session storage also
Related
I am trying to implement a Microservices project with a Blazor WASM front end. I am using Google as my identity provider, and have successfully setup authentication for the front end.
However, with the next step I want to send over my id_token and not my access_token to my Gateway API in order to confirm the user is authenticated when they are hitting my endpoints. I've read the documentation provided by Microsoft and there is no guidance on this. https://learn.microsoft.com/en-us/aspnet/core/blazor/security/webassembly/additional-scenarios?view=aspnetcore-5.0
I am trying to accomplish this myself by configuring the HTTP client at Program.cs, but can't figure out how to grab the id_token from the session storage.
builder.Services.AddHttpClient("GatewayApi", async client =>
{
client.BaseAddress = new Uri(builder.Configuration["GatewayServiceConfiguration:BaseUrl"]);
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", GOOGLE_ID_TOKEN_GOES_HERE);
});
I've only seen Blazor session storage available via razor pages, and never in the startup itself. Any suggestions?
I am trying to add anti-forgery to my asp.net core 3.1 web API by adding a filter in the startup file.
options => options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute())
This web API is consumed by my angular app which is hosted in a different port. I have done all the configuration which is specified in Microsoft docs as below.
app.Use(next => context =>
{
string path = context.Request.Path.Value;
if (path != null)
{
var tokens = antiforgery.GetAndStoreTokens(context);
context.Response.Cookies.Append("XSRF-TOKEN",
tokens.RequestToken, new CookieOptions
{
HttpOnly = false,
Path = "/",
}
);
}
return next(context);
});
In services
services.AddAntiforgery(options =>
{
options.HeaderName = "X-XSRF-TOKEN";
});
It generates two tokens one is.Asp.NetCore.AntiForgery and XSRF-TOKEN. I am getting this token in my client app and sending it to API as request header as x-xsrf-token but it fails every time. I have set up my cors to allow any origin. I am getting token as below in my angular app.
let xsrfToken = this.xsrfTokenExtractor.getToken() as string;
if(xsrfToken){
request = request.clone({headers: request.headers.set("X-XSRF-TOKEN", xsrfToken)});
}
Let me explain to you my flow. I have an identity server, web API, and angular app all of which are hosted in different ports. The angular app redirects to the identity server for authentication once it's done it will be redirected back to my client app. I have set up this csrf in web API. so basically, the authentication happens using a bearer token. I know that we don't need csrf protection because we already use a bearer token as my authentication mechanism. But I need it to work for csrf as well. Is there any way to achieve this?
I have a similar flow and I encountered a similar problem. In my case, I did not use the Configure method but instead I created a separate Endpoint that allows me to request the cookies.
var aft = _antiForgery.GetAndStoreTokens(HttpContext);
Response.Cookies.Append("XSRF-TOKEN", aft.RequestToken, new CookieOptions
{
HttpOnly = false,
Secure = true,
Domain = config.Domain
});
Initially I was doing the logging in part the cookie part in the same request and that lead to every request being rejected with a 400 Bad Request token but once I separated the login part and the cookies part in two separated endpoints and made two requests, everything worked as expected.
We have an ASP.NET MVC application based on the default Visual Studio SPA template. After a user successfully logs in, javascript reloads the page to call the OAuth authorize endpoint using this url
window.location = "/Account/Authorize?client_id=web&response_type=token&state=" + encodeURIComponent(window.location.hash);
Here is the server side code that handles bearer tokens
PublicClientId = "web";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
AuthorizeEndpointPath = new PathString("/Account/Authorize"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
The OAuth authorize endpoint responds with a 302 redirect with the access token in the url such as
https://example.com/#access_token=wKB_9sVptsGr...
Javascript extracts the token from the redirect url and uses that to authenticate with WebApi. This works beautifully as it allows us to be authenticated on both MVC side and WebApi side. However, this method of returning bearer tokens was identified as an issue during a recent cyber-security audit since the token is stored in the browser history exposing the access_token to other users.
Is there a better way to return a bearer token? We need both the MVC and the WebApi parts to be authenticated.
EDIT
Just to clear things up, this question is about the first time the server passes the access token to the browser. Not the browser passing the token back to the server.
I am working on configuring my OAUTH2 server to support the authorization_code flow, but I am hitting a wall trying to exchange an access code for an access_token. Every time I test the call I am getting back an invalid_grant error.
Here is how I understand the flow to work:
The client places a GET request to the oauth server authorize endpoint.
The oauth server validates the client and callback url
The oauth server sends the auth code in a querystring to the callbackurl.
The client (callbackurl) issues a POST request to the token endpoint with a grant_type of authorization_code with the code in the body of the request.
The OAuth server returns the client a token that may be used for requests.
The last method to fire in my code is the AuthenticationTokenProvider.Receive method, but I am getting an invalid_grant error instead of having a token generate. I presume this method should trigger another call someplace, and perhaps I am just missing something in my configuration.
Here is how I have configured OAuth in my environment:
var oAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = allowInsecureHttp,
TokenEndpointPath = new PathString("/oauth2/token"),
AuthorizeEndpointPath = new PathString("/oauth2/authorize"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
Provider = new CustomOAuthProvider(HlGlobals.Kernel),
AccessTokenFormat = new CustomJwtFormat(_baseUrl, HlGlobals.Kernel),
AuthorizationCodeProvider = new SimpleAuthenticationTokenProvider()
};
// OAuth 2.0 Bearer Access Token Generation
app.UseOAuthAuthorizationServer(oAuthServerOptions);
I am able to obtain an authorization code that gets sent to the callback url without issue.
Inside of postman I am using https://www.getpostman.com/oauth2/callback as my callback url. However, I have also tried placing the subsequent request to my token endpoint via a postman POST request as well. Both approaches produce the same result.
The second call, the POST call to the oauth server that includes the code in the body triggers the following events before returning a 400:
OAuthAuthorizationServerProvider - ValidateClientAuthentication
AuthenticationTokenProvider - Receive
In the receive method I verify that the code is valid before calling context.DeserializeTicket(value).
I understand the purpose of the ReceiveCode method to be removing the one time use code from the data store in addition to kicking off the token creation process.... but I am uncertain.
Any thoughts on what I am missing, and how I can implement the server code to exchange an auth code for an auth token using the authorization_code grant_type?
I am happy to supply any additional information upon request. Thanks!
I have two servers: one of them serves UI (it is called webUI) and another works with data (it is called webAPI).
I try to implement an authentication across the ADFS server. It has Relying Party Trusts for both servers: [urn=webui,identifier=address/webui],[urn=webapi,identifier=address/webapi].
I adjused the HttpConfiguration for webUI and user can be authenticated and use website, which the webUI serves (it's good).
var wsFedMetAdd = ConfigurationManager.AppSettings["wsFedMetAdd"];
if (string.IsNullOrWhiteSpace(wsFedMetAdd))
throw new ConfigurationErrorsException(Properties.Resources.InvalidMetadataAddress);
var wsFedWtrealm = ConfigurationManager.AppSettings["wsFedWtrealm"];
if (string.IsNullOrWhiteSpace(wsFedWtrealm))
throw new ConfigurationErrorsException(Properties.Resources.InvalidWtrealm);
appBuilder.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = WsFederationAuthenticationDefaults.AuthenticationType
});
var options = new WsFederationAuthenticationOptions
{
MetadataAddress = wsFedMetAdd,
Wtrealm = wsFedWtrealm,
SignInAsAuthenticationType = "Federation"
};
appBuilder.UseWsFederationAuthentication(options);
config.Filters.Add(new AuthorizeAttribute() { Roles = "Admin" });
Once client gets RequestSecurityTokenResponse (SAML Token). Also responses from ADFS set cookies for further requests (MSISAuth, MSISAuthenticated and so on).
The webAPI has the same implemention of HttpConfiguration (only one difference - wsFedWtrealm is urn:webapi instead urn:webui). Then I try send a request to the webAPI from client and the ADFS Server asks to authenticate one more.
I can't understand what should I do to use the same credentials for webAPI which I entered for webUI. Or maybe I should use SAML Token?
UPDATE
Wow. It is worked without SAML token, just using cookies.
When the user tries to be authenticated for webUI, diverse cookies are set on client (.AspNet.Federation, MSISAuth, MSISAuthenticated...). Then I substitute the webUI link with the webAPI link in the address bar and then webAPI doesn't ask to enter login and password. Hence data is displayed in browser. Authentication is picked up for webUI and for webAPI too.
But now problem is I get the error when javascript tries to send a request to webAPI:
XMLHttpRequest cannot load
https://my_address/adfs/ls/?wtrealm=urn%3awebapi&wctx=_ No 'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'https://my_address:9001' is therefore not allowed
access.
What version of ADFS?
You are mixing two protocols - Web API generally uses OAuth.
Use OpenID Connect for the UI and then that will naturally flow into the WebAPI as per this : Securing a Web API with ADFS on WS2012 R2 Got Even Easier.
Or for a somewhat more convoluted approach - what protocol to use with ADFS when security webapi for non-browser clients
This post help me to solve my problem.
I added to code of index.html new element iframe. Attribute src is the link to my webAPI.