How to unencrypt Web API 2 JWT tokens? - c#

I'm trying to work with the OAuth bearer tokens Web API 2 supplies but I don't know how to unencrypt them or get the data out.
What I'd really like to do is either find or write myself an equivalent tool to this Google Tool https://developers.google.com/wallet/digital/docs/jwtdecoder for the tokens I am getting from Web API. The Google tool allows you to paste in the string of text representing a JWT token and it splits it up and unencodes the JSON within.
In Visual Studio 2013 if you choose New ASP.NET project, and then choose the Web API template with individual user accounts you get a sample project that contains a token endpoint. If you start the project, you can then POST a request "grant_type=password&username=joe&password=joe" to /token on the built in webserver and you get a token back:
{
"access_token":"x3vHm40WUXBiMZi_3EmdmCWLLuv4fsgjsg4S5Ya8kppDY_-2ejn7qF5Y_nbQ0bYVIKl6MNzL2GtXv-MAuwjippAAv5VDaxoKdxEVxeFrQ_eXsKNaQK7IvmVs1rIZ9eeRfRGK2AQ59wWQcyTtYO0dPJx9K7PGrSKz4ADAZ9SEZqQ4IesVhYbRCwToyxoyU5L9qdU8jXdHumkIrULRQhf68rIaBrEA_Be-V0rzWJ644fRLvv3z69XoHs3Az7PineILyNwbDck9uU2jkaXnwxoCTa4qlK8bR-lEI9-VXPNdbCvfgb5H9wfYsJcw2CMzNxNhV8v9YVZEt90evylwtTCEpXq4T3zRCQvrpbCvZrXqJ8uvlFeqCsvvhlIkSfPhBY8nm2ocWtBGPZm58zLe5FMi1jept0B54U38ZxkZlrGQKar47jkmnc6gpLrkpDBp7cWz",
"token_type":"bearer",
"expires_in":1209599,
"userName":"joe",
".issued":"Fri, 01 Aug 2014 16:16:02 GMT",
".expires":"Fri, 15 Aug 2014 16:16:02 GMT"
}
What I want to find out is what format the access_token is in and what information is contained.
A clue I found was: you can choose what kind of tokens Web API uses by setting the OAuthAuthorizationServerOptions.AccessTokenFormat property in Startup.Auth.cs. The documentation for OAuthAuthorizationServerOptions says:
"The data format used to protect the information contained in the access token. If not provided by the application the default data protection provider depends on the host server. The SystemWeb host on IIS will use ASP.NET machine key data protection, and HttpListener and other self-hosted servers will use DPAPI data protection. If a different access token provider or format is assigned, a compatible instance must be assigned to the OAuthBearerAuthenticationOptions.AccessTokenProvider or OAuthBearerAuthenticationOptions.AccessTokenFormat property of the resource server."
So it's probably encoded using the MachineKey. That's fine, I can set the Machine Key OK but if I know the machine key that the token was created with, how do I decrypt it?

You are correct about the generation of the token. This token is an encrypted or signed string contains the de-serialized version of all the claims and ticket properties for the signed in user. If in IIS mode (SystemWeb), the encryption and signing is done via the "decryptionKey" and "validationKey" key values in machineKey node. If running as a self-host OWIN application, the encryption uses the DPAPI to protect it and that actually uses the 3DES algorithm.
To decrypt it you need to invoke this code in your API controller action method (not necessary but if you want to see what inside this encrypted token) :
string token = "Your token goes here";
Microsoft.Owin.Security.AuthenticationTicket ticket= Startup.OAuthBearerOptions.AccessTokenFormat.Unprotect(token);
If you need to configure your AuthZ server to issue JWT signed tokens so you can deconde them using someone line tool such as Google JWT decoder; then I recommend you to read my blog post here about JSON Web Token in ASP.NET Web API 2 using Owin

Related

How to retrieve OpenId / Keycloak bearer token when grant_type=authorization_code providing username & password using C#

UPDATE: I think Keycloak is the key. keycloak.js generates "data" parameter and makes a form post to retrieve token as json. Is there any equivalent in C#
I got a web site which updates json data and I need to log in and retrieve that json using C#. The site uses openid mechanism and I can log in and query the page using a browser, and then download fresh data if any.
I want to automate that process. At first I've used Fiddler to replay requests & responses but I noticed that browser uses javascript to generate a "data" variable.
So I am exploring for a library which automates retrieving authorization token what browser does simply providing "username" and "password".
This is the login form post:
A redirect:
Here is the "code" which one I failed to generate:
And the response got the bearer token:
As you see I have no specific clientid (it's "account") or clientsecret. Can someone who familiar with the process explain how can I automate the things using .NET Framework 4.8?

Is it possible to use impersonated access token within non-interactive session to get new access token to other Audience in Azure Active Directory?

Actors:
Black box (MS Power App custom connector) with user logged in
API A - .NET Standard WebApi with [Authorize] attribute and AAD authorization enabled (no additional verification in code), ida:audience="A" in web.config
API B - .NET Standard WebApi with [Authorize] attribute and AAD authorization enabled (no additional verification in code), ida:audience="B" in web.config
API C - .NET Standard WebApi with [Authorize] attribute and AAD authorization enabled (no additional verification in code), ida:audience="C" in web.config
Flow:
Power App connector calls API A. Within the code of API A (C#) I can decode JWT from Authorization header and see which user is logged in. Now, I have to call API B and API C and then return something to Power App connector. API B and API C must be able to also decode JWT and get UPN from token.
Problem:
When I tried to reuse whole Authorization header (just get it within API A and add to HttpClient to call API B and C) I get 401.
Now I know that was because of ida:Audience value. I suppose it is part of .NET framework verification, beyond my control. When I changed ida:Audience in API B and C to "A" it worked. But it was only for testing purposes, I am not allowed to do it in production.
Then I tried to set scopes in Power App connector to multiple values (delimited by space) with different audiences - no luck, error from AAD, multiple audiences not allowed.
So, my question is: is it possible in my scenario to do what I need? I have only access token for audience A and have to authorize (with impersonation) in endpoints with other audience value.
This is exactly what the on-behalf-of flow is for.
It allows API A to take the access token it received and ask for an access token to API B (with the same user info in the token).
More info on the flow: https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-on-behalf-of-flow.
Example request content from documentation to token endpoint that uses a client secret:
//line breaks for legibility only
POST /oauth2/v2.0/token HTTP/1.1
Host: login.microsoftonline.com/<tenant>
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
client_id=535fb089-9ff3-47b6-9bfb-4f1264799865
&client_secret=sampleCredentia1s
&assertion=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6InowMzl6ZHNGdWl6cEJmQlZLMVRuMjVRSFlPMCJ9.eyJhdWQiOiIyO{a lot of characters here}
&scope=https://graph.microsoft.com/user.read+offline_access
&requested_token_use=on_behalf_of
Using MSAL.NET is definitely better than using the HTTP endpoint directly though.
You would replace the scope in this request with a scope from API B.

Sign in to ASP.Net Core Web Application -> API with Individual User Accounts using Azure AD B2C ADB2C

I have set up a Web Application with ASP.NET Razor Pages with -> Individual User Accounts -> Connect to an existing user store in the cloud (Azure AD B2C).
This works really well and I could both sign up and sign in to the web application.
However when I follow the guide for API I don't understand how to sign in.
The example Controller /weatherforecast simply returns a HTTP 401 when the web application is started.
Looking at the file structure I can't find any clues either but this could be similar to scaffolding I guess.
https://stackoverflow.com/a/50677133/3850405
If I comment out [Authorize] from WeatherForecastController I get a HTTP 200 so what I need is probably just a token from Azure AD B2C that is being sent to the Controller in the GET request.
I know that the B2C tenant and application work since I use the same application for the API as I did with the Web Application. It was set up using Microsofts own guide:
https://learn.microsoft.com/en-us/azure/active-directory-b2c/tutorial-create-tenant
Update 2020-07-27:
Applications are now Legacy and App registrations should be used instead. See this guide:
https://learn.microsoft.com/en-us/azure/active-directory-b2c/tutorial-register-applications?tabs=app-reg-ga#register-a-web-application
Old:
Fixed it using these guides:
https://learn.microsoft.com/en-us/azure/active-directory-b2c/tokens-overview
https://learn.microsoft.com/en-us/azure/active-directory-b2c/access-tokens
I had some trouble where I got the error "AADB2C90205: This application does not have sufficient permissions against this web resource to perform the operation. numerous times. Turned out I had not declared the correct scopes for the application.
First step is therefore to make sure you have a read scope for your Azure AD B2C application under Published scopes:
Then under API access add your application with the scope read.
Then perform a GET request with this format, simplest way to test is to use it in Chrome or any other browser:
https://<tenant-name>.b2clogin.com/tfp/<tenant-name>.onmicrosoft.com/<policy-name>/oauth2/v2.0/authorize?
client_id=<application-ID>
&nonce=anyRandomValue
&redirect_uri=https://jwt.ms
&scope=https://<tenant-name>.onmicrosoft.com/api/read
&response_type=code
Make sure the redirect_uri is present as Reply URL for your application.
This should give you a result like after logging in like https://jwt.ms/?code=... or https//localhost:44376/signin-oidc?code= depending on redirect_uri. Microsoft example uses https://jwt.ms but I prefer to keep my codes on domains that I control.
Copy the value from code parameter and then perform a POST request, I use Postman.
POST <tenant-name>.onmicrosoft.com/oauth2/v2.0/token?p=<policy-name> HTTP/1.1
Host: <tenant-name>.b2clogin.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&client_id=<application-ID>
&scope=https://<tenant-name>.onmicrosoft.com/api/read
&code=eyJraWQiOiJjcGltY29yZV8wOTI1MjAxNSIsInZlciI6IjEuMC...
&redirect_uri=https://jwt.ms
&client_secret=<app-key>
client_secret is from Keys:
Correct response should look like this:
Then you can copy the value for access_token and access your local API with Bearer Authorization. To see the content of your access_token you can copy the value to https://jwt.ms/

JWT Authentication in Web API using System.IdentityModel.Tokens.Jwt

I am trying to implement JWT token based authentication in Web API using System.IdentityModel.Tokens.Jwt and Identity.
I am following this
Web.config
<appSettings>
<add key="issuer" value="http://localhost/" />
<add key="secret" value="IxrAjDoa2FqElO7IhrSrUJELhUckePEPVpaePlS_Xaw" />
</appSettings>
Though I was able to successfully able to implement and run the application with authentication, I am not sure what these settings are for. What ever I given in issuer, still the application works as expected. Can someone please provide some insights on issuer and secret?
I am using postman to test the token and the API
From the same site that you followed the tutorial (Create a RESTful API with authentication using Web API and Jwt) he says about the properties:
Issuer - a unique identifier for the entity that issued the token (not to be confused with Entity Framework’s entities)
Secret - a secret key used to secure the token and prevent tampering
But to try and explain this a little more precise:
The issuer is basically the server or site or whatever that issues the token to the client.
And the secret is something that the server (or whatever) knows about. The secret can be used to create a signature that can verify that messages hasn't been altered on the way. More on that on jwt.io JWT Secret :
To create the signature part you have to take the encoded header, the encoded payload, a secret, the algorithm specified in the header, and sign that.
Hope this helps!

How do I setup a valid on-premise ADFS URI?

I have a .NET 4.6.2 Windows client application which needs to get an authentication token from our on-premise ADFS server and use it to call an ASP.NET Core REST API. It's client name, id (GUID) and re-direct URI have been registered with ADFS. I am using the latest ADAL (v3.13) library to facilitate the authentication. I am attempting to get a token as demonstrated in the ADAL sample code like this:
AuthenticationContext authenticationContext = new AuthenticationContext("https://<adfs-sts-server>/<rest-api-host>", false);
var result = authenticationContext.AcquireTokenAsync(<rest-api-resource-uri>, clientId, redirectUri, new PlatformParameters(PromptBehavior.Auto));
The AcquireTokenAsync call returns an error, saying: The browser based authentication dialog failed to complete. Reason: The server has not found anything matching the requested URI (Uniform Resource Identifier).
Can anyone tell me:
Is the "requested URI" refered to in the error the https://<adfs-sts-server>/<rest-api-host> or <rest-api-resource-uri>?
Do I need to register <rest-api-host> or <rest-api-resource-uri> with ADFS in some way, and if so how?
Any other information I need to get this to work?
Thanks!
Peter
Using Active Directory Federation Services (ADFS) to provide authentication for on-premise endpoints from a Windows Client
Configuring ADFS
There are 2 parts to configuring ADFS.
Register the client application with ADFS
ADFS needs to be able to identify the application requesting user authentication, whether it be a service, WPF application, Web client or Office Add-in. I have gone generic and added the following client, which we can use for most of our C# requests; we may need to register a new client with different callback for Web clients.
Use one of the many tools out there to generate a GUID for the client ID.
* CLIENT_ID and APP_NAME should be unique.
* For a web client the redirect URI is where the auth service will redirect your call after authenticating the user. It should be an endpoint where you can process the token and continue with your client application. The redirect URI is not really used with rich clients/services/add-ins.
CLIENT_ID = 26E54EC9-7988-4DAE-A527-483A8A78B1C6
APP_NAME = Investplus
DESCRIPTION = Invest+ rich client suite
REDIRECT_URI = https://server/redirect-adfs.html
Instructions for Client registration
(may be possible in a wizard, but this is what I found on the web and it worked fo us)
Log on to the AD FS server as administrator and open a Windows PowerShell command window.
Enter the following command. In Windows PowerShell
Add-AdfsClient -ClientId <CLIENT_ID> -Name <APP_NAME> -RedirectUri <REDIRECT_URI>
Register the resource to be accessed ('Relying Party' in ADFS speak)
I found this link useful, it takes you through the steps of the wizard for setting up a relying party.
Instructions for Relying Party registration
The administrator on the server team will need to use the ADFS Add Relying Party Trust Wizard, and under the "Select Data Source" step select Enter data about the relying party manually.
Values you need to supply for this wizard:
DISPLAY_NAME = "MyInvestApi" (Unique display name for this Relying party)
PROFILE = "AD FS Profile"
ENABLE_SUPPORT_FOR_WS-FEDERATION_PASSIVE_PROTOCOL = true
URL = "https://server/api" (Unique URL for this RP)
ADD_ONE_OR_MORE_IDENTIFIERS = eg. "urn:myInvestApi" and "https://server/api"
ACCEPT_REMAINING_DEFAULTS
when given the opportunity, Add Claim Rules:
SEND_LDAP_ATTRIBUTES_AS_CLAIMS = true
ATTRIBUTE_STORE = Active Directory
SELECT_USEFUL_ATTRIBUTES = User-Principal-Name; Email; Display-Name
Configuring/Coding the Client application
Microsoft provides Active Directory Authentication Libraries (ADAL) for a range of platforms and languages from C# to Javascript, and from iOS to Cordova to Node.
The API exposed has changed significantly in each major version: I am using the latest C# library, currently 3.13.5.
The library makes the coding very simple, just a few lines; where I had problems was:
I couldn't find an explanation of what URL to use for the ADFS
Secure Token Service (STS)
I couldn't find documentation of the whole process as I am doing here (most documentation focussed on Azure FS), I struggled to work out
how the values provided to ADFS for Client and Relying party mapped
to the values used in the code.
What is the ADFS endpoint/URL to use in code?
Microsoft's best practice is to name your ADFS/STS server URL https://sts.domain.com (some people use https://adfs.domain.com, ask your server admins). However, if you try to hit this from a browser you'll get a 404 - Not found and trying to retrieve a token in the code, the ADAL library reports:
The browser based authentication dialog failed to complete. Reason: The server has not found anything matching the requested URI (Uniform Resource Identifier).
This is how I found the endpoint to use:
ADFS pubishes federation metadata at 'https://sts.domain.com/federationmetadata/2007-06/federationmetadata.xml'
Extract this file and open in a text editor.
When configuring the Relying Party, we specified "Enable Support for WS-Federation Passive Protocol" when specifying our resource endpoint, so search the XML for PassiveRequestorEndpoint.
Use the <Address> from this node - in my case https://sts.domain.com/adfs/ls/. I don't know if this will always be the value, or if it is specified when ADFS is setup and therefore potentially different per site.
What other values to use in the code?
We want our client app to retrieve a JSON Web Token (JWT) from ADFS which we can pass to our protected resource for authentication/authorization purposes.
At its most simple, the access token can be retrieved in 3 lines of code + configuration, and this will show how to translate what we have configured in ADFS to the values required by ADAL:
var stsEndpoint = "https://sts.domain.com/adfs/ls/";
var relyingPartyIdentifier = "urn:myInvestApi"; // Tenant in Azure AD speak, but this is an on-premise service
var authority = stsEndpoint + relyingPartyIdentifier;
var restResourceUrl = "https://server/api";
var redirectUri = "https://server/redirect-adfs.html";
const string CLIENT_ID = "26E54EC9-7988-4DAE-A527-483A8A78B1C6";
AuthenticationContext authenticationContext = new AuthenticationContext(authority, false);
var asyncRequest = authenticationContext.AcquireTokenAsync(restResourceUrl, CLIENT_ID, redirectUri, new PlatformParameters(PromptBehavior.Auto));
var accessToken = asyncRequest.Result.AccessToken;
Useful references
ASP.NET Core Token Authentication Guide
ADAL - Native App to REST service - Authentication with ACS via Browser Dialog
Create a line-of-business Azure app with AD FS authentication
OAuth 2 Simplified
To issue the token for the web API, we need to make the ADFS to aware it by creating a relying party trust for the web API. And when we add a replying party we need to specify the identifiers for the replying party like figure below(Windows Server 2012 R2):
Then we can use this identifiers as the resource URI to acquire the token for this replying party. Please ensure that the resource URI is correct as you config like figure above.
And here is an article about developing with ADFS using OAuth:
Developing Modern Applications using OAuth and Active Directory Federation Services
Depending on the version of asdf, you may be able to use 'discovery' to obtain the endpoints to use.
Have a look at this post for more details: http://www.cloudidentity.com/blog/2015/08/21/openid-connect-web-sign-on-with-adfs-in-windows-server-2016-tp3/

Categories

Resources