I have a project which uses IdentityServer3 for Auth as a Service.
Recently I was tasked with creating a seamless experience for End-Users to edit their identity information.
I did this by creating an API Controller in my application which uses a HTTPClient to call another API Controller living in my IdentityServer project. It basically exposes the Identity management methods to the world, but "passes-through" any requests on to the IdentityServer Api.
All is well right up until I call the IdentityServer Api Controller. My breakpoint there is never hit, regardless of the presence of a "Authorize" attribute. I end up receiving a "401: Unauthorized" back from the IdentityServer Api controller.
I've tried to reuse the original request's Auth headers, but that didn't work. I also tried to find a "access_token" claim from my claim principle, but one wasn't found.
here is a code snippet:
var httpClient = new HttpClient();
// this didn't work - tried reusing the auth from the original request
//httpClient.DefaultRequestHeaders.Authorization = request.Headers.Authorization;
// this didn't work either - "access_token" is not found
//httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", Caller.FindFirst("access_token").Value);
var routePrefix = GetRoutePrefix();
var response = await httpClient.PostAsync(
$"{routePrefix}/post",
new ObjectContent(typeof(TDObj), entity, new JsonMediaTypeFormatter()));
return response;
I'm new to IdentityServer3 and OAuth and not sure what to do next. I tried creating a new scope for "identity" and tried to make it a required scope in my client application, but that didn't seem to do the trick. I know I'm missing some key piece of understanding here, but there is so much documentation for IdentityServer, I don't know where to begin and can't find anything specific to this need. I'm in the weeds! Can anyone help me understand what's going on here? Thanks!
I got it working by following Scott Brady's answer here: Identity Server and web api for user management
However, his answer didn't immediately work for me. I had to make sure to make the call for UseIdentityServerTokenValidation to happen BEFORE api route mapping happened.
That being said, my original attempt to hi-jack the Authorization headers from the inbound HTTPRequest of my Front-End application worked, so I was able to remove any code requesting an access token and didn't have to SetBearerToken() on my HttpClient. Just this:
httpClient.DefaultRequestHeaders.Authorization = request.Headers.Authorization;
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'm using the below code to get access token and refresh token from docusign.
But I'm always getting the invalid-grant error. I'm pasting the code below.
[HttpGet("GetDocToken")]
[AllowAnonymous]
public async Task<IActionResult> getToken(string docCode)
{
var x = docCode.Length;
var client = new HttpClient();
var authCode=Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes("ced8998a-4387-4f30-9ab7-51c0d1af49bf:d7c3ccd4-22fa-4f18-a540-ddf11d8b2c9f"));
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", authCode);
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));
var requestContent = new FormUrlEncodedContent(new[] {
new KeyValuePair<string, string>("grant_type", "authorization_code"),
new KeyValuePair<string, string>("code", docCode),
new KeyValuePair<string, string>("redirect_uri", "http://localhost:4200/auth")
});
HttpResponseMessage response = await client.PostAsync("https://account-d.docusign.com/oauth/token", requestContent);
string resultContent = response.Content.ReadAsStringAsync().Result;
return Ok(response.Content.ReadAsStringAsync());
}
My assumption is that you have received the authentication code back from the DocuSign identity system and are trying to exchange it for an access token.
A couple of issues:
The docs incorrectly indicates that the redirect_uri should be included in the request. The Example Request in the docs does correctly show that the request should only include the grant_type and code parameters.
Note: While the OAuth standard, section 4.1 (d) does indicate that the redirect_url should be included, DocuSign usually does not include it.
My guess is that DocuSign will ignore the redirect_uri parameter, but you might want to try leaving it out.
Another issue is timing: The authorization code you receive back from DocuSign is only good for a minute or so. If you're not immediately using the authorization code (your code's docCode) then you'll get the Invalid Grant error.
Known good example software
I suggest that you also check out the known-good code example for C#. You can use a protocol peeker to see exactly what it is doing during the authentication.
Use a library
I also suggest that you look for an OAuth Authorization Code client library that you can use instead of rolling your own.
For example, are you setting and checking the state value? It's important to do that to stop CSRF attacks. See this article.
Added
It is also not clear to me that you are using the right value as the authorization code.
I believe the flow should be:
User presses "Authenticate with DocuSign" in the Angular app.
User's browser does a GET to the DocuSign authentication server. At this point, the browser is no longer running the Angular app.
User's browser and DocuSign Authentication server exchange HTML back and forth as the user authenticates with DocuSign.
The user completes the authentication process with DocuSign.
DocuSign sends a REDIRECT response to the browser, telling the browser to do a GET on the redirect url. The redirect (and the GET) include query parameters for code and state
Your SERVER (not the Angular app), receives the GET request.
Your server should:
Extract the code and state query parameters
Verify that state is the same as was sent in step 2.
Makes the POST request to DocuSign to exchange the authorization code for an access token.
RESPONDS to the browser with the Angular program.
The Angular program is now once again running on the browser.
Use Implicit Grant
Your other option is to use Implicit Grant. That way you don't need a server component. With Implicit Grant, your Angular program handles the flow.
I am trying to get access to OneDrive for Business using OAuth2.0 authentication protocol. I have followed this example:
http://msdn.microsoft.com/EN-US/library/dn605894(v=office.15).aspx
an this is my code so far:
// Create an authentication context
AuthenticationContext ac = new AuthenticationContext(string.Format("https://login.windows.net/{0}",
ClaimsPrincipal.Current.FindFirst(TenantIdClaimType).Value));
String id = ClaimsPrincipal.Current.FindFirst(TenantIdClaimType).Value;
// Create a client credential based on the application id and secret.
ClientCredential clcred = new ClientCredential(AppPrincipalId, AppKey);
// Using the authorization code acquire an access token.
var arAD = ac.AcquireTokenByAuthorizationCode(code, new Uri(appRedirect), clcred);
I am getting a Authorization code is malformed error. I don't understand why I am getting this message.
Any help would be appreciated!
Had the same issue when I was trying to get authorization code manually and then use it from console application. Not sure why it doesn't work for me.
But when I use it from Web App, the same app which performed authorization and received code in return (because I specified it as returnURL) - everything works.
I suggest you to have a look on this example
https://github.com/AzureADSamples/WebApp-WebAPI-OAuth2-UserIdentity-DotNet
And also this article to understand what's happening under the good:
http://blogs.msdn.com/b/exchangedev/archive/2014/03/25/using-oauth2-to-access-calendar-contact-and-mail-api-in-exchange-online-in-office-365.aspx
P.S.
It's not a OneDrive, but I had exactly the same problem, so if you can make it working with Exchange or GraphApi, then it should work for OneDrive as well.
Authorization code is malformed error is occured if you send the auth code in incorrect format. May be the authorization code which you are sending is encoded value of authcode and session state. you need to seperate both values and send the auth code only. or decode the '&' symbol(seperator) between auth code and session state and send them as two parameters.
The method AcquireTokenByAuthorizationCode(...) from ADAL4j takes only authcode.
I'm currently trying to create a proof of concept for claims based authentication for a new app using a combination of the following technologies: Web API 2, OWIN middleware and JWT.
To keep things simple I started with the Web API 2 project template and changed the authentication to 'Individual User Accounts'. The sample client I created was then able to get a token by calling /Token and was able to call a sample endpoint with the OAuth bearer token. So far so good. I then added the following code to Startup.Auth.cs to try and enable JwtBearerAuthentication:
var jwtOptions = new JwtBearerAuthenticationOptions
{
AllowedAudiences = audiences,
IssuerSecurityTokenProviders = new[] {
new SymmetricKeyIssuerSecurityTokenProvider(issuer, signingKey) }
};
app.UseJwtBearerAuthentication(jwtOptions);
I expected that Web API 2 would start returning JWTs from the call to /Token, but it doesn't appear to have done anything. I've been banging my head against this for a few days with no success and the Microsoft documents aren't very forthcoming.
I also tried adding the following to my OAuthAuthorizationServerOptions
AuthorizationCodeFormat = new JwtFormat(audience, new SymmetricKeyIssuerSecurityTokenProvider(issuer, signingKey))
I could also be trying to doing the completely wrong thing.
Any ideas would be greatly appreciated.
Well, now there is a setting on OAuthAuthorizationServerOptions that you can specify the format of your access token, not the authorization code, like you're doing on you example.
So, instead of:
AuthorizationCodeFormat = new JwtFormat(audience, new SymmetricKeyIssuerSecurityTokenProvider(issuer, signingKey))
You should have:
AccessTokenFormat = new JwtFormat(audience, new SymmetricKeyIssuerSecurityTokenProvider(issuer, signingKey))
The Windows Identity Foundation uses a proprietary token format, not JWT. The JWT code you see above is for consuming tokens, not generating them. There is a helpful discussion on the ASP.NET forums.
However, in the second half of 2014 Microsoft officially released support for JWT in Windows Identity foundation, with the JSON Web Token Handler. You should be able to install and use that package to solve the problem you have described.
I don't think there's any current way to override how the token is output in the response. I took a look at the OAuthAuthorizationServerHandler in the Katana source code repository.
You'll see that in the InvokeTokenEndpointAsync method, there is a section that creates a JsonTextWriter which generates the response. It is not done in such a way that any kind of extension would affect it.
I find this frustrating too. Microsoft's library should have some way to easily override the response serialization. You can't even add your own custom parameters to the response.
You can use this sample https://github.com/thinktecture/Thinktecture.IdentityModel/tree/master/samples/OAuth2/EmbeddedResourceOwnerFlow
for writting authentication logic in your project.
After it you must add [Authorize] attribute to each controller or action which requires authorization(OWIN Katana contains the logic of validating token, authorization and some other useful things).
I'm just finishing authorization and resource server for OAuth2, using DotNetOpenAuth 4.3.4. For testing, I created test client by implementing OAuth2Client.
Because I'm using DNOA for all the communication and request parsing, I'm not sure if I fully understand what is going on under the hood. But this knowledge is very important when I make documentation.
So, could you please explain to me, how client authentification works in DNOA? I use authorization code as grant_type and when I use my test client to exchange code for access_token, the DNOA somehow validate the client_secret and client_id. I downloaded source code for DNOA, but it not helped.
When I set breakpoint to Oauth2 controller(token method) and parse the request as HttpRequestMessage, i see the request contains "grant_type", "code" and "redirect_uri". But where are client_id and client_secret?
Also, can you tell me where I can find any usable documentation for DNOA? I need to create documentation, which will be valid and usable for all platforms, not just C#, which can use DNOA.
Related question:
I somewhere read, that we should not create authorization codes for unauthentificated clients, but this is exactly what DNOA does (since I receive authorization code even if secret is wrong). Is it ok?
Edit:
This is the request I'm trying to read. It is token request made by DNOA client. I can not see the client_id and client_secret under other parameters like "code", "redirect_uri" and "grant_type". I tought they have to be together. Maybe I'm missing something important from http requests and responses.
When I let DNOA to HandleTokenRequest(request) to continue, it is successfully authenticate the client application (fails when bad secret is set in DNOA client app config).
Edit 2
private readonly WebServerClient Client;
protected override string QueryAccessToken(Uri returnUrl, string authorizationCode)
{
var authorization = Client.ProcessUserAuthorization();
if (authorization != null)
return authorization.AccessToken;
else
return null;
}
This is my implementation of QueryAccessToken. It is from some sample. I think I created this at the beginning and did not change it, because it worked.
Going rought DNOA source I found out it is method from OAuth 1. THis can be the problem. But the question is, why it works ok with right client cerdentials and not working with bad ones.
Final edit
Looks like DNOA client uses http Basic authorization (client_id and secret are in header). But I need the DNOA server to be able to grab these parameters from POST.
If anyone know how to set DNOA to support client_id and client_secret in POST parameters, it would be awesome!
Thank you
The authorization code grant requires two steps.
The first step is the browser redirecting to the identity provider and displaying the logon ui. The authorization code is returned to the browser by the identity provider and then, from the browser to the client application. This step doesn't involve client secret! This is because the end user can debug this part of the flow and she should not learn the value of the client secret.
Then, when the client application has the onetime authorization code, it concacts the token endpoint directly (server-to-server) to exchange the authorization code for authorization token. This is where client id and client secret are used to verify that only legitimate client applications exchange codes for tokens.
The idea behind this flow is to protect the end user from exposing her password to the client application and also protect the client application from exposing its client secret to the end user.
Also note that the authorization code grant flow is the most complicated one as it involves both username/password (provided by the end user) and clientid/client secret (provided by the client application). There are other flows which allow to get the authorization token in slightly different way, namely:
resource owner grant which involves sending username/password directly by end user to the token endpoint of the identity provider. This flow is suited for desktop/mobile/native apps where the logon ui can be customized (but it also can raise suspicions and users could proably refuse to use it)
client credentials flow which involves sending clientid/client secret by the client application to the idntity provider. There is no end user but only the client application authenticating in the identity provider.
More on flows here:
http://aaronparecki.com/articles/2012/07/29/1/oauth2-simplified
As for DNOA, I found it clean and understandable but the docs are lacking. Fortunately, examples are great and although barely documented, you can find almost everything there. Nonetheless, I was able to set up oauth2 identity provider and resource server in three days and support all four oauth2 flows. I am not going to dig deeply into details as this is not what your question is about, however, if you have DNOA specific questions, just ask.
Edit:: regarding your QueryAccessToken implementation, it seems that you are using the WebServerClient internally. In my code I just initialize its properties:
WebServerClient client = ...
client.ClientIdentifier = "client_id";
client.ClientCredentialApplicator =
ClientCredentialApplicator.PostParameter( "client_secret" );
With these two configured, both client_id and client_secret are sent to the token service with the client_secret passed in POST params.