How to issue and consume JWT using ServiceStack's JwtAuthProvider - c#

Looking at the JwtAuthProvider documentation for ServiceStack, it seems that a lot of JWT functionality is given out-of-the-box. However I really need to look at some working example. I could not find any in the example directory for ServiceStack.
What I'd like to see, is an example code that shows:
How to issue a token with some claims.
How to decode the token and inspect the claims.
Just using some "Hello world" service. Does anyone have some code that shows this or know where to look?
Ideally, the signing would use RSA, but right now this is not that important...
Thanks.

The JWT AuthProvider is what Issues the JWT token which it populates based on the User Session. You can add your own metadata in the tokens and inspect it with the CreatePayloadFilter and PopulateSessionFilter.
JWT is enabled in both the AngularJS http://techstacks.io Example by just making a call to /session-to-token after the user successfully authenticates with their OAuth Provider, e.g:
$http.post("/session-to-token");
This converts their currently authenticated session into a JWT Token which it uses for future subsequent requests.
Likewise JWT is also used in http://gistlyn.com which uses a Customized JwtAuthProvider to embed the Github OAuth Access Token Secret into the JWT Token then uses the PopulateSessionFilter to extract it from the JWT Token and populate it back in the Users Session:
appHost.Plugins.Add(new AuthFeature(() => new AuthUserSession(),
new IAuthProvider[] {
new GithubAuthProvider(appHost.AppSettings),
//Use JWT so sessions survive across AppDomain restarts, redeployments, etc
new JwtAuthProvider(appHost.AppSettings)
{
CreatePayloadFilter = (payload, session) =>
{
var githubAuth = session.ProviderOAuthAccess.Safe()
.FirstOrDefault(x => x.Provider == "github");
payload["ats"] = githubAuth != null
? githubAuth.AccessTokenSecret : null;
},
PopulateSessionFilter = (session, obj, req) =>
{
session.ProviderOAuthAccess = new List<IAuthTokens>
{
new AuthTokens { Provider = "github", AccessTokenSecret = obj["ats"] }
};
}
},
}));
Gistlyn uses a similar approach to TechStacks to using JWT Tokens by calling /session-to-token after the User has authenticated with Github OAuth using JavaScript's new fetch API
fetch("/session-to-token", { method:"POST", credentials:"include" });
JWT Stateless Auth Tests
For other examples you can look at JWT RSA Tests which uses CreateJwtPayload which shows examples of manually creating JWT Tokens in code.

Related

What is the best practice for fetching User data after validating JWT in .NET Core 2 Web Api?

I am moving from MVC to a SPA + API-approach on a new application im making and am facing some questions I cant seem to find the answer for.
I have a Web API in .Net Core 2 that is using Identity for its user-store. I am protecting the API by issuing JWT-tokens which my SPA is sending in as a bearer-token on every request to my controllers. The issuing code is:
private async Task<object> GenerateJwtTokenAsync(ApplicationUser user)
{
var roles = await _userManager.GetRolesAsync(user);
var claims = new List<Claim>
{
new Claim(JwtRegisteredClaimNames.Sub, user.Email),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(ClaimTypes.NameIdentifier, user.Id)
};
claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role)));
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JwtKey"]));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var expires = DateTime.Now.AddDays(Convert.ToDouble(_configuration["JwtExpireDays"]));
var token = new JwtSecurityToken(
_configuration["JwtIssuer"],
_configuration["JwtIssuer"],
claims,
expires: expires,
signingCredentials: creds
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
My question is: What is the best practice for getting user information needed to serve the request in the controller?
As Im getting the JWT-token I have the user-information, but the extended information on the user, such as which company they work for is in my SQL-database.
// GET: api/Agreements
[HttpGet]
public async Task<IEnumerable<Agreement>> GetAgreementsAsync()
{
var user = await _userManager.GetUserAsync(HttpContext.User);
return _context.Agreements.Where(x => x.CompanyId == user.CompanyId);
}
Do I need to make another turn to the DB to get this information on each request? Should this information be put in the JWT-token, and in that case, in which field to you put "custom"-information?
Preferably when authorizing you would like to stay stateless, which means that when client passes authentication and gets JWT token, then server can authorize requests with the JWT token on the fly. Which means that server won't look for JWT token anywhere, not in database or memory. So you don't have overhead of looking in database or elsewhere.
To answer your question you should also know the reason behind Claims: "The set of claims associated with a given entity can be thought of as a key. The particular claims define the shape of that key; much like a physical key is used to open a lock in a door. In this way, claims are used to gain access to resources." from MSDN
You don't need to make another request to DB, but keep in mind that Claims are best used for authorization purposes, so mainly add extra claims in JWT so you can later authorize for API resources without going to the database. You can also add your custom claims to then token which then get encrypted into JWT Token and sent to the client.
After authentication you can store the companyId and/or userId in the claims and you can name any string you would like, because that's how claim's constructor is implemented. And when the request arrives you can get the companyId from the claims. For example name it simply "companyId".
var claims = new List<Claim>
{
new Claim(JwtRegisteredClaimNames.Sub, user.Email),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(ClaimTypes.NameIdentifier, user.Id),
new Claim("companyId", user.companyId.ToString()) // Like this
};
And then write getter for the company id claim
HttpContext.User.FindFirst("companyId").Value
Also keep in mind that, for complex user data you shouldn't use claims like this because this data pass in network and you don't want huge JWT Tokens. Also it is not good practice, for that you can use HttpContext.Session where you can store data and get it when the request comes. This is not place to write in detail about Session storage.

Using OAuth2 eBay authentication with .NET SDK

I have been searching throughout the internet for a solution to use OAuth2 user token with eBay's .NET SDK and could find ANY SINGLE solution. The code I have is like following:
var ctx = new ApiContext();
ctx.Version = "897";
ctx.ApiCredential.ApiAccount.Application = "//something here";
ctx.ApiCredential.ApiAccount.Developer = "//something here";
ctx.ApiCredential.ApiAccount.Certificate = "//something here";
ctx.ApiCredential.eBayToken = "v^1.1... // this is OAuth2 token";
var getUser = new GetUserCall();
getUser.OutputSelector = new string[] { "UserID","Site" };
getUser.GetUser();
What I find really irritating is the fact that there is a possibility to use the new OAuth2 token with trading API, and I know this for a fact, because if you add an HTTP header to any Trading API call like:
X-EBAY-API-IAF-TOKEN:q2eq2eq2eq2q2eq2e
It will work, but I haven't found anywhere in the documentation to pass the IAF-TOKEN (OAuth2) token via .NET SDK calls...
Has anyone else been trying this? Is there nay way to pass the OAuth2 token via .NET SDK and then fetch the results ?
Because if I try to pass the OAuth2 token like this:
ctx.ApiCredential.eBayToken = "v^1.1... // this is OAuth2 token";
In place where the traditional Auth'n'Auth token went, I'm getting the following error:
validation of the authentication token in api request failed.
Can someone help me out please ?!

How to convert bearer token into authentication cookie for MVC app

I have a 3 tier application structure. There is a cordova js application for end-users, an implementation of identityserver3 which serves as the OpenID authority, and an MVC app which will be access through an in-app browser in the cordova application.
The starting entry point for users is the cordova app. They login there via an in-app browser and can then access application features or click a link to open the in-app browser and visit the MVC app.
Our strategy for securing the MVC website was to use bearer token authentication, since we already logged in once from the app and didn't want to prompt the user to login again when they were directed to the MVC app:
app.Map("/account", account =>
{
account.UseIdentityServerBearerTokenAuthentication(new IdentityServer3.AccessTokenValidation.IdentityServerBearerTokenAuthenticationOptions()
{
Authority = "https://localhost:44333/core",
RequiredScopes = new string[] { "scope" },
DelayLoadMetadata = true,
TokenProvider = new QueryStringOAuthBearerProvider(),
ValidationMode = ValidationMode.ValidationEndpoint,
});
}
Since persisting the access_token on the query string is painful, I implemented a custom OAuthBearerAuthenticationProvider:
public class QueryStringOAuthBearerProvider : OAuthBearerAuthenticationProvider
{
private static ILog logger = LogManager.GetLogger(typeof(QueryStringOAuthBearerProvider));
public override Task RequestToken(OAuthRequestTokenContext context)
{
logger.Debug($"Searching for query-string bearer token for authorization on request {context.Request.Path}");
string value = GetAccessTokenFromQueryString(context.Request);
if (!string.IsNullOrEmpty(value))
{
context.Token = value;
//Save the token as a cookie so the URLs doesn't need to continue passing the access_token
SaveAccessTokenToCookie(context.Request, context.Response, value);
}
else
{
//Check for the cookie
value = GetAccessTokenFromCookie(context.Request);
if (!string.IsNullOrEmpty(value))
{
context.Token = value;
}
}
return Task.FromResult<object>(null);
}
[cookie access methods not very interesting]
}
This works, and allows the MVC application to not have to persist the access token into every request, but storing the access token as just a generic cookie seems wrong.
What I'd really like to do instead is use the access token to work with the OpenID endpoint and issue a forms-auth style cookie, which responds to logout. I found that I can add account.UseOpenIdConnectAuthentication(..) but if I authenticate via access_token, the OpenIdConnectAuthentication bits are simply skipped. Any ideas?
You don't -- access tokens are designed to be used to call web apis. You use the id_token from OIDC to authenticate the user and from the claims inside you issue your local authentication cookie. The Microsoft OpenIdConnect authentication middleware will do most of this heavy lifting for you.

Validating ADAL JWT token in C# REST service

I have a web application which uses the ADAL library for authentication through Azure Active Directory.
This web application makes a call to a C# REST service by passing the ADAL token string as a parameter. In my REST service, I want to validate this token. If the token is valid only then the service will perform the operation.
I searched a lot but could not find a way to validate the JWT token in my rest service. Can you guys please help me on this?
You have two options:
1. Use OWIN middleware
Use middleware that will handle token validation for you. A common case will be the OWIN middleware, which does all the magic for you. Usually, this is the best approach, as it allows you to focus your code on the business logic for your API, not on low-level token validation. For a sample REST API that uses OWIN, check out these two samples:
https://github.com/Azure-Samples/active-directory-dotnet-webapp-webapi-openidconnect
https://github.com/Azure-Samples/active-directory-dotnet-webapp-webapi-openidconnect-aspnet5
2. Manual JWT validation
You can use the JSON Web Token Handler for ASP.NET to do manual JWT token validation. (Ok, so it's not entirely manual, but it is manually invoked.) There's also a sample for this:
https://github.com/Azure-Samples/active-directory-dotnet-webapi-manual-jwt-validation (the actual JWT validation happens in Global.asax.cs and looks something like this:
JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
TokenValidationParameters validationParameters = new TokenValidationParameters
{
ValidAudience = audience,
ValidIssuer = issuer,
IssuerSigningTokens = signingTokens,
CertificateValidator = X509CertificateValidator.None
};
try
{
// Validate token.
SecurityToken validatedToken = new JwtSecurityToken();
ClaimsPrincipal claimsPrincipal = tokenHandler.ValidateToken(jwtToken, validationParameters, out validatedToken);
// Do other validation things, like making claims available to controller...
}
catch (SecurityTokenValidationException)
{
// Token validation failed
HttpResponseMessage response = BuildResponseErrorMessage(HttpStatusCode.Unauthorized);
return response;
}

Verify Access Token - Asp.Net Identity

I'm using ASP.Net Identity to implement external logins. After user logins in with Google I get google's external access token. I then make a second api call to ObtainLocalAccessToken() which trades the external access token for a new local one.
ObtainLocalAccessToken() calls VerifyExternalAccessToken() which verifies the external access token with the provider by manually making http calls and parsing the user_id.
How can I leverage ASP.NET identity to remove the entire method VerifyExternalAccessToken()?
I believe that's what [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)] is for isn't it? I want to decorate ObtainLocalAccessToken() endpoint with that attribute and send the external_access_token in the header ({'Authorization' : 'Bearer xxx' }), and it should populate User.Identity without needing to manually verify the external access token? I believe that’s the purpose, however I cannot get it working. I send a valid external access token from google and it gets rejected with a 401.
I have this line in Startup.Auth btw:
app.UseOAuthBearerTokens(new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(),
AuthorizeEndpointPath = new PathString("/AccountApi/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
});
Alternatively, it is possible to use "/Token" endpoint to trade an external access token for a local one? Which approach is correct?
Studying the implementation by Taiseer Joudeh
the /ExternalLogin endpoint replaces the OWIN Authentication Challenge.
The AngularJS LoginController makes a call to the authService.obtainAccessToken when an externally authenticated user has not been found in Identity Provider:
if (fragment.haslocalaccount == 'False') {
...
}
else {
//Obtain access token and redirect to orders
var externalData = { provider: fragment.provider,
externalAccessToken: fragment.external_access_token };
authService.obtainAccessToken(externalData).then(function (response) {
$location.path('/orders');
It uses the VerifyExternalAccessToken to perform a reverse lookup against Google and Facebook API's to get claim info for the bearer token.
if (provider == "Facebook")
{
var appToken = "xxxxxx";
verifyTokenEndPoint = string.Format("https://graph.facebook.com/debug_token?input_token={0}&access_token={1}", accessToken, appToken);
}
else if (provider == "Google")
{
verifyTokenEndPoint = string.Format("https://www.googleapis.com/oauth2/v1/tokeninfo?access_token={0}", accessToken);
}
else
{
return null;
}
If token is found, it returns a new ASP.NET bearer token
var accessTokenResponse = GenerateLocalAccessTokenResponse(user.UserName);
return Ok(accessTokenResponse);
With [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)] the OWIN Middleware uses the external bearer token to access the 3rd party's Cookie and Register a new account (Or find existing).
OWIN Middleware cannot be configured to accept external bearer token instead of local authority tokens. External bearer tokens are only used for Authentication and Registration.

Categories