Consuming Rest API with .Net HttpClient fails Authorization when Access Token is not gotten directly - asp.net-core-mvc

The server is a .net core API that uses Identity for authentication/authorization and SimpleTokenProvider for generating the JWT tokens. The particular endpoint requires a role authorization.
[Authorize(Roles = "Admin")]
When I get a token from a different controller action method, saves the token in a session and tries to use that token to call the API, or when I hard-code a token gotten from Postman and passes it to the API, the user gets authenticated on the server, but fails to authorize.
The only way the user gets authorized is if I request for the token inside the same controller action method. It also works fine from Postman.
The client code is as below:
string token = "ew0KICAiYWxnIjogIkhTMjU2IiwNCiAg...";
HttpClient client = new HttpClient(handler);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
HttpResponseMessage httpResponse = client.GetAsync("http://localhost:5001/api/dashboard").Result;
if (httpResponse.IsSuccessStatusCode)
{
Console.Write(httpResponse.Content.ReadAsStringAsync().Result);
}
From the server logs, the authorized calls for the same endpoint has the following:
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://localhost:5001/api/dashboard
Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware:Information: HttpContext.User merged via AutomaticAuthentication from authenticationScheme: Identity.Application.
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware:Information: Successfully validated the token.
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware:Information: HttpContext.User merged via AutomaticAuthentication from authenticationScheme: Bearer.
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:Information: Authorization was successful for user: xxxxx.
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:Information: Authorization was successful for user: xxxxx.
While the unauthorized calls has the following logs:
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://localhost:5001/api/dashboard
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware:Information: Successfully validated the token.
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware:Information: HttpContext.User merged via AutomaticAuthentication from authenticationScheme: Bearer.
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:Information: Authorization was successful for user: xxxxx.
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:Information: Authorization failed for user: xxxxx.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
Microsoft.AspNetCore.Mvc.ChallengeResult:Information: Executing ChallengeResult with authentication schemes ().
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware:Information: AuthenticationScheme: Bearer was forbidden.
Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware:Information: AuthenticationScheme: Identity.Application was challenged.
I don't know what other option needs to be added to HttpClient for the authorizations to work.

After using wireshark to trace the difference in the requests from HttpClient and Postman, i discovered that .Net Identity sets a Cookie named .AspNetCore.Identity.Application after a user signs in which must be sent as part of the requests for the authorization to work.
After getting the cookie and setting it as part of the subsequent requests, it works fine.

Related

Authenticate opaque token in the spring security oauth server

Using the old authorization server, the user request an opaque token using the Client credentials grant and then use it inside an Authorization Header when calling APIs. On our resource server, we would contact the authorization server to authenticate this token and retrieve client information.
On the new server, we have no problem generating this opaque token but I don't understand how we can authenticate this token ?
When calling the introspection endpoint, we have always an Unauthorized result due to using AnonymousAuthenticationToken: obviously since the user is already logged in, we don't ask him to give his client_id and client_secret for each call.
Is it possible to allow this behavior ?
Calling the introspection endpoint and having a success with the decrypted token metadata and not a 401.

openiddict - The specified authorization code is invalid

I have written a web API in .NET core 2.0 and using openiddict. When testing the external login use case, the following steps are followed.
User calls into account controller specifying their external login provider which starts the Challenge process.
/api/account/externallogin?provider=Facebook
The result of the Challenge process calls back to API (ExternalLoginCallback) with successful result and redirects to the following API endpoint to return an authorization code to the client via the redirect_uri.
/connect/authorize?client_id=myClient&response_type=code&scope=offline_access&redirect_uri=http://myClient/signin-oidc";
The client receives the code via the redirect_uri with code appended as shown below
http://myClient/signin-oidc?code=CfDJ8Agzs3e68m5Ev0zC5okWI7--_T13E-ULHqeUlzgmEWBcPj6PYBBzAWu0kssa0wl3OcYX-YG0jCzhLZr2Wajvjc_zJTsmK12rmRjPAzqbqu9OuMjDX-wzNQYMI0cpLW1ZuumvPZHiRP5hxWAVpgH1pu5VwdcQBTBpyOPOP0JD2Wba1VAF9iopN1YIquLkvtVXnJEEKhb1apqfJAkA_NNk2lSRxFBkq6rFn9wLEOt2y9b0fOqsJ0sqmA1jbhJVfiVPaaI8z3J8HnzFtMwNHTwgpU8gAjk9ZTeTuP86nxQZl8R-P7LgEvOs8AgTR1g_WBSZgwtPfpULV3Ib7iUn8BQ4PiDhcwVR3Wed9Utnmbx5w8iDV9-jo4QRleuH8QWmZxXqr2nyeeCKqC01VHoEGl1KJak1jcxzFg7ooZAM_yrD207n0jy-hX9dvyl6XezSND5-ltjWjM1b96iK_74X8Euf4YVlhcV2bWPzBmgBSWQydOfT_xv3HNmXQcWwXjlEcCaxzdAKTconRDUuycBsdLS1Je6cME5deT9fzp98Lt6ryuVGNtkkqGg0LcKv49JmPyiBHrQfQUOUQg8fXkCYrf7k8FG5N8e-k3X1P3NEcYFcMchxF_1s1T2lUGAfmJ3P8Yqd9j26PF-gWzQHwkcdz1ptwbIXmF-tHuQK8zmIHoa5ErB3lR5bffsZmmG77NpTT-yq82Bbl5yf32RXKunqf5rQrVF7cWX0eM1h-EDgeHiMwx2IOYkHcxK6JLcRlggDfG__wMn_vEsQwW5UJaKU1VywT3hBGvS-zmbseparILu8hGDL5DrpmLpE3a5obWsp1yCM33fb7ciYmWuwQXKldG7MWXg#=
Client immediately extracts the code from the URL and posts to the following endpoint to receive access/refresh tokens, but receives an error of invalid grant with error description of The specified authorization code is invalid.
/connect/token
The following values are submitted in the post to request access token:
grant_type = authorization_code
code =
CfDJ8Agzs3e68m5Ev0zC5okWI7--_T13E-ULHqeUlzgmEWBcPj6PYBBzAWu0kssa0wl3OcYX-YG0jCzhLZr2Wajvjc_zJTsmK12rmRjPAzqbqu9OuMjDX-wzNQYMI0cpLW1ZuumvPZHiRP5hxWAVpgH1pu5VwdcQBTBpyOPOP0JD2Wba1VAF9iopN1YIquLkvtVXnJEEKhb1apqfJAkA_NNk2lSRxFBkq6rFn9wLEOt2y9b0fOqsJ0sqmA1jbhJVfiVPaaI8z3J8HnzFtMwNHTwgpU8gAjk9ZTeTuP86nxQZl8R-P7LgEvOs8AgTR1g_WBSZgwtPfpULV3Ib7iUn8BQ4PiDhcwVR3Wed9Utnmbx5w8iDV9-jo4QRleuH8QWmZxXqr2nyeeCKqC01VHoEGl1KJak1jcxzFg7ooZAM_yrD207n0jy-hX9dvyl6XezSND5-ltjWjM1b96iK_74X8Euf4YVlhcV2bWPzBmgBSWQydOfT_xv3HNmXQcWwXjlEcCaxzdAKTconRDUuycBsdLS1Je6cME5deT9fzp98Lt6ryuVGNtkkqGg0LcKv49JmPyiBHrQfQUOUQg8fXkCYrf7k8FG5N8e-k3X1P3NEcYFcMchxF_1s1T2lUGAfmJ3P8Yqd9j26PF-gWzQHwkcdz1ptwbIXmF-tHuQK8zmIHoa5ErB3lR5bffsZmmG77NpTT-yq82Bbl5yf32RXKunqf5rQrVF7cWX0eM1h-EDgeHiMwx2IOYkHcxK6JLcRlggDfG__wMn_vEsQwW5UJaKU1VywT3hBGvS-zmbseparILu8hGDL5DrpmLpE3a5obWsp1yCM33fb7ciYmWuwQXKldG7MWXg#=
redirect_uri = http://myClient/signin-oidc"
cient_id = myClient
client_secret = mySecret
scope = offline_access role email openid

Spring Security: How to pass oauth2 access token in request headers

On successful login to my spring security application configured with Oauth2, I received a response with Oauth2 token.
For the subsequent request I passed Oauth2 access_token in URI Query Parameter like this
http://localhost:8090/myapplication/users/user?access_token=4c520795-eb07-4c2d-a91b-474c85fb481e
It is working fine.
But instead of passing token in URI to make it more secure I wanted to send token in request headers.How to do this?
Use the usual HTTP Authorization header:
Authorization: Bearer <your-token-here>
For example
Authorization: Bearer 4c520795-eb07-4c2d-a91b-474c85fb481e

ServiceStack Jwt authentication check if authenticated

I need to allow anonym access endpoint but still check if user is authenticated then give some extra data.
using [Authenticate] attribute I can use
var session = SessionAs<AuthUserSession>();
and then session.IsAuthenticated
it works just fine but without [Authenticated] attribute session is empty(new session is generated with new id and all props is not populated with user data)
How to check if user is authenticated without [Authenticate] attibute with request which uses jwt token?
The JwtAuthProvider is an IAuthWithRequest provider which only validates the JWT Token and returns the appropriate HTTP Error Response if the token is invalid when it needs to Authenticate the the Request, e.g. when Services annotated with the [Authenticate] attribute. If Services don't require Authentication, the IAuthWithRequest Auth Providers and JWT Bearer Tokens aren't validated and the Users Session isn't automatically populated.
But in the latest v4.5.9 that's now on MyGet new APIs have been added to JWT AuthProvider to be able to create custom JWT Tokens and convert them into User Sessions, specifically you can create a UserSession from a JWT Token with:
var session = JwtAuthProvider.CreateSessionFromJwt(base.Request);
Which is just a helper for resolving the registered JwtAuthProviderReader and calling its ConvertJwtToSession() API:
var jwtProvider = (JwtAuthProviderReader)
AuthenticateService.GetAuthProvider(JwtAuthProviderReader.Name);
var session = jwtProvider.ConvertJwtToSession(base.Request, base.Request.GetJwtToken());

Sending Bearer Tokens to Web API via Postman

Update
I have been able to get a Bearer token using instructions from this thread
Here are the instructions in Postman:
Url: https://login.windows.net/[tenantname].onmicrosoft.com/oauth2/token
Type: POST
Headers: none
Body: form-data
grant_type: client_credentials
client_id: [client-id]
client_secret: [client-secret]
However, if I send the same token in my call to a Web API endpoint, I still get back "Authorization has been denied for this request"
Why is it still not authorizing ?
End Update
I have created an ASP.Net Web API project which is protected using an organizational Azure AD instance. I have set up the tenant id, client id and secret correctly.
The Azure AD instance is the same one backing our Office 365/SharePoint instance and the idea is to create SharePoint Add-Ins which can call the services using the logged in user's context.
I am stuck at testing the API. I can call unauthorized endpoints without any issue. However, when I add the [Authorize] attribute, I always get back this response: "Authorization has been denied for this request."
As I understand it, I need to generate a bearer token and add it to my Postman request in the header (see image). After much Googling, I still have not been able to make this work.
My question is: How do I generate a bearer token for a Web API instance protected by Azure AD.
My configuration code is as below:
public void ConfigureAuth(IAppBuilder app)
{
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
Tenant = ConfigurationManager.AppSettings["ida:Tenant"],
TokenValidationParameters = new TokenValidationParameters {
ValidAudience = ConfigurationManager.AppSettings["ida:Audience"]
},
});
}
First, you can use POSTMAN to test web api protected by the Bearer token. Here's my postman screenshot:
POSTMAN sending bearer token to web api
Basically: in the request header, specify the key as "Authorization", and value as "Bearer [your token". IF you run into errors, look the headers of the response and you'll see more detailed error info.
Note, most tokens have an expiration period, you can try to verify if your token is valid. e.g. https://jwt.io/

Resources