I developped an api using spring boot withuser authentication and authorizations with spring securtiy.
And I am using spring security login form for user authentication.
I tested it with postman and it is working perfectly.
But when I implemented the api in asp.net mvc 5 project the login works and return the connected user but i get unauthorized message after any other request that needs authenticated user.
I think it works in postman because he generates or get headers from response of login.
How can i get them so i can integrate them in other requests.
Edit:
It seems that JSESSIONID Cookie header is needed and I took it from login response header and added it to my request header but it still doesn't work
Here is my code that adds the header:
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("Cookie", loginResponse.Headers.GetValues("Set-Cookie").First().Split(';')[0].Trim());
client.DefaultRequestHeaders.Add("Cache-Control", "no-cache");
client.BaseAddress = new Uri("http://localhost:8080/api/");
HttpResponseMessage response = client.GetAsync("customer/users").Result;
This line give me the Cookie header value from login response i need:
loginResponse.Headers.GetValues("Set-Cookie").First().Split(';')[0].Trim()
HttpClient will ignore header Cookie
when creating an instance to it you need to pass an HttpClientHandler with UseCookies to false so it will not ignore it
HttpClient httpClient = new HttpClient(new HttpClientHandler { UseCookies = false })
Answer found here
Related
I have a .NET Core 3.1 Api application with the following configuration of HttpClient. In Startup.cs
services.AddAuthentication(IISDefaults.AuthenticationScheme);
services.AddHttpClient("myapi", c =>
{
c.BaseAddress = new Uri(Configuration["endpoint"]);
c.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue(
IISDefaults.AuthenticationScheme, Convert.ToBase64String(
System.Text.Encoding.UTF8.GetBytes($"{Configuration["username"]}:{Configuration["password"]}")));
});
I then try to make an HTTP call like this:
var client = clientFactory.CreateClient(clientName);
HttpResponseMessage response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
return await response.Content.ReadAsStringAsync();
however I always get an Unauthorized response when calling an internal api. Under Debug I have Windows authentication and Anonymous authentication both enabled.
With Postman my api calls go through, which verifies that I got the right credentials.
Can you suggest any alterations to make this work?
Instead of c.DefaultRequestHeaders.Authorization =, I'm having config like this
c.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
{
Credentials = new NetworkCredential("username", "password"),
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate,
PreAuthenticate = true
});
I guess this will not work as-is in your case, but I hope this can get you on track.
I have a ASP.Net Core MVC Web App that users needs to logon to get the id_token from the IdentityServer4 and then that id_token will be passed to webapi implemented in ServiceStack to obtain the authorization code. The subsequent call to the webapi will use the authorization code.
So far what I have read is for the Web App, it should use openid cookie token (UseOpenIdConnectAuthentication). For the webapi, it should use the bearer token. My question is how I can pass that http only cookie token from the client side browser as a bearer token in the http header. As the cookie is http only, it can't be accessed by the Javascript. Moreover, the ASP.NET Core cookie middleware encrypts the cookie, can that encrypted cookie be decrypted by the ServiceStack webapi (if the cookie is passed to the webapi)?
Am I going in the right direction? Any suggestion is welcome.
Thanks
You can find an example of your scenario here: https://identityserver4.readthedocs.io/en/release/quickstarts/5_hybrid_and_api_access.html
The authorization code is only used to get access tokens from the identity server, it is not used to authenticate to APIs.
Here is how the flow should work:
User logs in at Identity Server
Your MVC app gets an authorization code and id token
The id token tells your MVC app who the user is
The authorization code is exchanged for an access token and refresh token with identity server for the API
Now the MVC app can make HTTP calls from its backend using the access token
Authentication cookie is created and returned to user
Front-end submits the authentication cookie with every request to MVC backend, which authenticates every request automatically that hits MVC, then when you want to call the API from there, get it as shown in the docs, and attach it to your requests
I think the point you are missing here is that once the user is logged in, you will get the access token in the response as well when you land back on the client application. If you are using Hybrid Flow, on the client app we configure it as
app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
{
AuthenticationScheme = "oidc",
SignInScheme = "Cookies",
Authority = "http://localhost:5000",
RequireHttpsMetadata = false,
ClientId = "mvc",
ClientSecret = "secret",
ResponseType = "code id_token",
Scope = { "api1", "offline_access" },
GetClaimsFromUserInfoEndpoint = true,
SaveTokens = true
});
See the ResponseType we ask for code i.e the access code. So you need not to call or login again. Once you want to call your api just get the token like
var access_token = await HttpContext.Authentication.GetTokenAsync("access_token");
// call api
var client = new HttpClient();
client.SetBearerToken(access_token);
var response = await client.GetAsync("http://localhost:5001/identity");
if (!response.IsSuccessStatusCode)
{
Console.WriteLine(response.StatusCode);
}
else
{
var content = await response.Content.ReadAsStringAsync();
Console.WriteLine(JArray.Parse(content));
}
And if you using Implicit flow, your front end can get the access token using oidc-client library and user.access_token will have it.
I have recently started a Web API 2 project in Visual Studio 2012 using OWIN middleware to authenticate users with OAuth2. I incorporated token based authentication as outlined on this tutorial (Token Based Authentication). The authentication part works great. I have added some testing API methods and I wanted to hook up Swagger for my API documentation. I got that part working too, with the exception that the API calls from Swagger fail on authorization.
After research, I found Erik Dahl's post about how to hook up Swagger to OWIN middleware. After I configured my Swagger according to the post, I now see the authenticate buttons on the Swagger UI next to each API method. However, when trying to authenticate, the authentication within Swagger is done using a GET request. The authentication on the web API though requires it to be POST request. Is it possible to configure Swagger make the authentication request a POST? If not, should I allow my API to accept GET requests for token authentication? What would be the best approach to make this work?
Note: The request still hits my authentication logic, but the client_id and client_secret are not passed in a GET request, only in a POST request.
Here's my Swagger config:
httpConfig
.EnableSwagger(c =>
{
c.SingleApiVersion("v1", "Sample API");
c.ApiKey("token")
.Description("API Key Authentication")
.Name("Bearer")
.In("header");
c.OAuth2("oauth2")
.AuthorizationUrl("/oauth/token")
.Flow("implicit")
.Description("OAuth2 authentication")
.Scopes(scopes =>
{
scopes.Add("sampleapi", "Sample API");
});
c.OperationFilter<AssignOAuth2SecurityRequirements>();
})
.EnableSwaggerUi(c =>
{
c.EnableOAuth2Support(
clientId: "Sample_App",
clientSecret: "xxxxx",
realm: "test-realm",
appName: "Swagger UI");
});
And here's my OAuth config:
app.CreatePerOwinContext<ApiClientRepo>(ApiClientRepo.Create);
app.CreatePerOwinContext<MeetingRegistrantRepo>(MeetingRegistrantRepo.Create);
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
//For Dev enviroment only (on production should be AllowInsecureHttp = false)
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/oauth/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new CustomOAuthProvider(),
AccessTokenFormat = new CustomJwtFormat("http://localhost:51071"),
RefreshTokenProvider = new SimpleRefreshTokenProvider()
};
// OAuth 2.0 Bearer Access Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
No, I would not change the authentication method from POST to GET just to satisfy Swagger.
I found another article which should help you do what you want to do here : http://danielwertheim.se/use-identityserver-in-swaggerui-to-consume-a-secured-asp-net-webapi/
It wold be worth to try it that way. Don't forget that changing from POST to GET means you can no longer pass the parameters in the body of the request and you will instead have to do it in the URL of the request and that makes the whole thing insecure.
Yes, the ClientID and ClientSecret will still be part of the Authorization Header, but still do not open yourself up to stuff like this. Swagger should not dictate the architecture of your API so don't go there.
I am trying to authenticate RESTful service (sabre REST api) using RESTsharp library but i am not able to authenticate it. I am using my Client id and secret. Please tell me how to authenticate using oAuth 2.0 authenticator.
I have tried this code. ( sabre is using OAuth 2.0 authentication )
public ActionResult Index()
{
var client = new RestClient("https://api.test.sabre.com");
client.Authenticator = new HttpBasicAuthenticator("myclientid", "myclientsecret");
RestRequest request = new RestRequest("/v1/auth/token", Method.POST);
request.AddHeader("Authorization", "Basic " + client);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddParameter("grant_type", "client_credentials");
IRestResponse response = client.Execute(request);
var content = response.Content;
ViewBag.R = content;
return View();
}
i got this result
{"error":"invalid_client","error_description":"Credentials are missing or the syntax is not correct"}
please tell what i am doing wrong.
Thanks
Snapshot of Fiddler Comparison of Running code (not with RestSharp) and code using RestSharp is shown
With RestSharp
Seems to me like you are adding the Authorization header twice. The documentation here says
The authenticator’s Authenticate method is the very first thing called
upon calling RestClient.Execute
Looking at the implementation of HttpBasicAuthenticator, the Authenticate method adds the appropriate header to the request.
So remove the following line from your example:
request.AddHeader("Authorization", "Basic " + client);
You need to first obtain access token from Sabre that you can later use while making rest api calls.
The access token POST request looks like this:
POST https://api.test.sabre.com/v2/auth/token
Authorization: Basic ZVc5MWNtTnNhV1Z1ZEdsazplVzkxY21Oc2FXVnVkSE5sWTNKbGRBPT0=
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
where the value of Authorization after Basic is the Base64 encoded string based on your clientId and secret
Refer to Sabre Authentication on how this string is created
So, in order to get the access token you just need to send a POST request with required header and request parameters and you do not need to use the Authenticator
We're trying to send Google Authentication tokens to our Rest interface on Google App Engine.
As explained here (under heading "Calling a Google API")
https://developers.google.com/accounts/docs/OAuth2InstalledApp
We should do this by including an Authorization: Bearer HTTP header.
On the client side we're using;
public ClientResource getClientResource(Reference pReference, String pAccessToken)
{
ClientResource lClientResource = new ClientResource(pReference);
ChallengeResponse lChallengeResponse = new ChallengeResponse(ChallengeScheme.HTTP_OAUTH_BEARER);
lChallengeResponse.setRawValue(pAccessToken);
lClientResource.setChallengeResponse(lChallengeResponse);
return lClientResource;
}
So the ChallengeResponse with setRawValue() is used to set the header;
ChallengeResponse lChallengeResponse = new ChallengeResponse(ChallengeScheme.HTTP_OAUTH_BEARER);
lChallengeResponse.setRawValue(pAccessToken);
lClientResource.setChallengeResponse(lChallengeResponse);
For our J2SE clients this is working. Although there's an error message;
"Challenge scheme HTTP_Bearer not supported by the Restlet engine."
we're able to read the token on the server side with;
ChallengeResponse lChallengeResponse = pRequest.getChallengeResponse();
String lAccessToken = lChallengeResponse.getRawValue();
While this is working for our J2SE clients, our GWT clients always return lChallengeResponse == null
Is this the correct method to set the Authorization: Bearer HTTP header or should we add extra/other configuration options?
Why isn't this working for our GWT clients (return null)?
How do we get rid of the error message on our J2Se clients?