Web Api OWIN - How to validate token on each request - c#

I have two applications
Client application build on ASP.NET MVC
Authentication server build on Web API + OWIN
Have planned authentication as follow
For user login client app will make a request to authication server with logged in credential.
Authication server will generate a token and will send back to client application.
Client application will store that token in local storage.
for each subsequent request client app will attached token kept in local storage in request header.
NOW, ON SERVER SIDE OF CLEINT APP I NEED TO VALIDATE THAT TOKEN COMES WITH EACH REQUEST IS NOT TEMPERED.
Please suggest me how to validate token in each request as i don't know the key the OWIN has used to generate the token.
Is is right to write code to validate token on client app or it should be on authication server.
I am planning to shift all user management code like register user, change password to authentication server so than we can re-use it for different client app- is it right design practice?
So far i have wrote below code to just to create a POC.
=========================OWIN configuration========
[assembly: OwinStartup(typeof(WebApi.App_Start.Startup))]
namespace WebApi.App_Start
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
ConfigureOAuth(app);
WebApiConfig.Register(config);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
}
public void ConfigureOAuth(IAppBuilder app)
{
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = false,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new SimpleAuthorizationServerProvider(),
};
// Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(new
OAuthBearerAuthenticationOptions());
}
}
}
==============================oAuth Provided========================
public class SimpleAuthorizationServerProvider: OAuthAuthorizationServerProvider
{
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
using (AuthRepository _repo = new AuthRepository())
{
IdentityUser user = _repo.FindUser(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
}
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim("sub", context.UserName));
identity.AddClaim(new Claim("role", "user"));
context.Validated(identity);
}
}
Please help,
Thanks,
#Paul

Please suggest me how to validate token in each request as i don't
know the key the OWIN has used to generate the token.
Your current setup, were you have added the app.UseOAuthBearerAuthentication() to the owin pipeline, will authenticate the user from the bearer token which is passed on each request for you.
The current user can then be found via HttpContext.Current.User.
Use the Authorize attribute to then decide which users are authorized on certain endpoints.
Here's an example where users with the role "user" are allowed to access
[Authorize(Roles="user")]
public class ValuesController : ApiController
{
}
Is is right to write code to validate token on client app or it should
be on authication server.
NO, you don't validate the token in client, if your user credentials are wrong you wont get a token at all. That's all you need to know.
And also, why should you want to validate the token in the client?
I am planning to shift all user management code like register user,
change password to authentication server so than we can re-use it for
different client app- is it right design practice?
Reusing a token provider is common. Why invent the wheel for every application? Build one great, or use a third party, and reuse it across your applications.

Use JSON Web Tokens (JWT) and claims identities, not random tokens that require keeping track of the issued tokens.
A JWT is like a passport issued by a trusted authority. The passport is signed/stamped, and you can verify that it was issued by this trusted authority and that it has not been tampered with. That means, the integrity of the access-right claim present in the token can be verified without keeping state anywhere. The only communication that needs to happen between the trusting application and the authority is an initial (secure) download of the authority's public key (used for signing the tokens).
It's also advisable that you use a standard claims schema, like OpenID Connect ( http://openid.net/specs/openid-connect-core-1_0.html#StandardClaims )
A good book on the topic, which helped me a lot getting an understanding of all these concepts, can be found here: A Guide to Claims-Based Identity and Access Control.

One way to verify a token has not been tampered is to sign it using an asymmetric key pair, Identity Server uses this approach as seen here.
In your case if you are rolling your own authentication you will need to implement this yourself, and check on every request probably in a custom middleware that the token is valid.

If you create, sendback, save in localStorage and every thing about JWT Token as correct, you have to know that many ways are in .Net that you can to controlling per request.
Server side controlling:
If you are using Web API Core, in core you can create Middleware that runs as pipline in run time, and you can give context and check token that requested, for more infomation check: This.
If you use of Asp.net MVC, you can use ActionFilter in MVC(Asp.Net-Core have more advance ActionFilter too), that each requests goes through on and you can check every thisng abount request, for more information check: This.
ClientSide Conftolling:
After that you give Token after log in from server side, you have to save data in localstorage that your browser check per request that data, they advantage are the Expireation and every like this issue in token save in localstorage and you and browser can use of this for more information check: This.
GoodLuck.

Related

How to Authenticate two subdomain by one login in IdentityServer?

I have an IDP server implemented by Duende IdentityServer assume which is hosted on idp.com and there are two separate ReactJS applications hosted on app.mysite.com and profile.mysite.com and they are using JWT token for authentication and authorization process. now when I login into app.mysite.com through idp.com profile.mysite.com is un unauthenticated and needs another login. I use the same client configuration for both of these sites. I know there are some methods such as using an IFRAME inside client code to share the JWT token between these two app but I am looking for a built-in approach inside the Identity server to solve this issue?
First of all, if you have 2 CLIENTS, you should configure 2 separate configurations for both of them.
Afer separation of clients you should rely on cookie set on idp.com after first authentication. (Good to know - How to setup cookie authentication basic cookie authentication: https://learn.microsoft.com/pl-pl/aspnet/core/security/authentication/cookie?view=aspnetcore-6.0)
Anyway, if you configured IdentityServer properly, it handles cookie authentication "out-of-the-box" - so probably the only thing you have to do is to Signin the user.
AuthenticationProperties props = new AuthenticationProperties
{
IsPersistent = true,
ExpiresUtc = DateTimeOffset.UtcNow.Add(LoginOptions.RememberMeLoginDuration)
};
var issuer = new IdentityServerUser(user.SubjectId)
{
DisplayName = user.Username
};
await HttpContext.SignInAsync(issuer, props);
When the youser want to login to second application, after start of the flow (eg. code flow) and redirect to the idp.com, idp.com knows that the user is already signed-in (cookie) and should immediately generate token and redirect back to the return url.
If you need you can adjust custom behaviours using IProfileService.

IdentityServer4 - Delegated access tokens for clients

In IdentityServer4 you can specify an extension grand to enable delegated access tokens for users, so if a webservice needs to call another webservice during a request from a user, it can request a new access token from the IdentityServer with a valid scope and audience. My issue is, that this grant is thought to be used "on behalf of the interactive user", which leads to my question:
If my client calls a webservice which needs to call another webservice during the request, how can i create a delegated access token?
I tried to modify the example from the documentation, but the extension grand expects a token from a user, which holds a "sub" claim, and not from a client, which does not hold a "sub" claim.
The client is a daemon application, so it runs fully automated and without any user interaction, and is authenticated with the client credentials flow.
To clarify what i mean:
Here we see an use case, if a user is present:
User accesses a UI
UI redirects the user to the identity server to authenticate (With the Authorization Code Flow + PCKE). The UI gets the access token back
The UI calls an WebApi A with the access token
The WebApi A needs to access the WebApi B, but the access token was meant for WebApi A. Therefore the WebApi A asks the IdentityServer for a delegated access token to access WebApi B.
The IdentityServer provides the delegated access token.
The new access token is passed along to the WebApi B.
Here we see the same use case, but no user is present and a daemon application does the same thing:
The deamon appliaction authenticates against the IdentityServer with the Client Credentails Flow and gets the access token back
The deamon appliaction calls an WebApi A with the access token
The WebApi A needs to access the WebApi B, but the access token was meant for WebApi A. Therefore the WebApi A asks the IdentityServer for a delegated access token to access WebApi B.
How to get the IdentityServer to provide a the delegated access token for the client?
The new access token is passed along to the WebApi B.
For machine to machine (Service to service) communication you typically use the client credientials grant. This allows services to communicate even if no user is present. The userid (Subject) is typically included in the API calls that is protected using this flow.
See this article
The communication between WebApi-A and WebApi-B can be done using client credentials flow and here you don't need to pass any access token from the user. Instead you pass the subjectId(userID) and optionally some additional claims as part of the API calls between A and B. This way is much simpler and the benefit is that A-B can communicate without any user involved (for example to do workflow style communication in the background).
I have found the solution to my issue. You can extend the given example implementation of the delegation grand and extend it in a way, that a delegation token is issued for a client:
public async Task ValidateAsync(ExtensionGrantValidationContext context)
{
var oldToken = context.Request.Raw.Get("token");
if (string.IsNullOrEmpty(oldToken))
{
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant);
return;
}
var result = await _validator.ValidateAccessTokenAsync(oldToken);
if (result.IsError)
{
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant);
return;
}
var sub = result.Claims.FirstOrDefault(c => c.Type == "sub")?.Value;
if (sub != null)
{
// The old token had a user context
context.Result = new GrantValidationResult(sub, GrantType);
}
// The "magic" is the part below
else
{
// The old token had a client context
var client = result.Claims.FirstOrDefault(c => c.Type.Equals("client_id", StringComparison.Ordinal));
if (string.IsNullOrWhiteSpace(client?.Value))
{
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidClient);
return;
}
context.Request.ClientId = client.Value;
context.Result = new GrantValidationResult(new Dictionary<string, object>());
}
}

How to use ASP.net 5 Identity in web API application? User authentication based on tokens. Mobile apps

Assuming that I currently have a newly created project based on Visual Studio 2015 "WebApp" template with Individual Accounts authentication, I use Microsoft.AspNet.Authentication package and I can't always rely on cookies, because my web API should also target mobile apps:
How can I add authentication to my web API? I'm especially interested in token based authentication.
You can use basic http authentication or implement a similar one with a token or ticket passed through http headers.
Implement custom AuthorizeAttribute in your web api project. In IsAuthorized(HttpActionContext actionContext) overload you can check the authorization scheme and authorization header and then you can connect to your sessions provider and check if the user has an active session.
You must pass the login token in the authorization header, so if the token is missing that means there is no active user.
So when you login you must create and encrypt the token on successful login. Then pass this token with each request to the server.
This blog contains more information about using AuthorizeAttribute: http://weblogs.asp.net/jongalloway/asp-net-mvc-authentication-customizing-authentication-and-authorization-the-right-way
You can make separate table in db for storing authentication detail (AuthKey, UserID, CreatedDate, ExpiredDate, IsExpired) and make functions like CheckAuthorizationKey(string authKey), ExtendAuthorization(string authKey), ExpireAuthorization(string authKey){}
and call that functions for checking the authorization as below sample code.
public ServiceResult<LoginModel> Login(string auth_key)
{
var service = new ServiceResult<LoginModel>();
LoginModel user = new LoginModel();
if (AuthKey.CheckAuthorizationKey(auth_key) == false)
{
service.message = TemplateCodes.GetMessage(TemplateCodes.UnAuthorize, null, db);
service.status = ServiceStatus.authorization_failed;
return service;
}

Retrieve bearer token in ASP.NET WebAPI

I have a Web API with authentication enabled (bearer token). This is called by a client application and I want to protect it from anonymous usage so I would like to create a single user and create a bearer token for it.
I can create the token by calling the register and token methods, but I would like to do this from code.
As far as I know, the bearer token is not stored in the database. Can it be retrieved somehow using the ASP.NET Identity API?
I would also like to create this user from code and save the token somewhere because I need to deploy the database to multiple servers.
I do not recommend going with this approach if you have only one client who will talk to your API, my understanding that you need to issue a very very long lived access token maybe for a year and keep using this token to access the back-end API, right?
What you will do if this token is stolen? You can't revoke the access token, so it is somehow like your master key (password).
My recommendation is to use OAuth refresh tokens along with access tokens. This depends on the type of your client, you can check how this is done here http://bitoftech.net/2014/07/16/enable-oauth-refresh-tokens-angularjs-app-using-asp-net-web-api-2-owin/
The refresh tokens can be revoked and they can expire after a very long time. Let me know if you need further details to implement this.
Create a Custom Authentication Attribute and store the token hashes for users. A user can have multiple tokens. Then you can let user do what he wants - log out all other sessions when password is changed or remove sessions selectively
public class CustomAuthAttribute : System.Web.Http.AuthorizeAttribute
{
protected override bool IsAuthorized(HttpActionContext context)
{
var accessToken = HttpContext.Current.Request.Headers["Authorization"];
var hash = accessToken.Md5();
//store the hash for that user
//check if the hash is created before the password change or its session was removed by the user
//store IP address and user agent
var isBlackListed = ...
.....
return !isBlackListed && base.IsAuthorized(context);
}
}
If you're needing to decode the token within a WebAPI Controller function, I found this worked:
String token = Request.Headers.Authorization.Parameter;
Microsoft.Owin.Security.AuthenticationTicket t = Startup.OAuthOptions.AccessTokenFormat.Unprotect(token);

Web API authorization access_token validation

Now I am working with authorization with OAUTH2.0.
I want to do my own authorization server(WEB API).
I have a Dummy MVC project to test this.
I succeeded to create some access token in server(WEB API) using 'SimpleAuthorizationServerProvider'.
I have to call some API Calls but should authorized.
so I can send this call with my token like.
https://localhost/Profile?access_token=...
or can send access_token through header.
This much is OK now from my side.
But I need to validate this access_token in server side.
I can get access token from client(Dummy MVC project).
private static TokenResponse GetToken()
{
var client = new OAuth2Client(new Uri("http://localhost:2727/token"),"client1", "secret");
var response = client.RequestResourceOwnerPasswordAsync("bob", "bob").Result;
return response;
}
But could not uderstand where it's created from server side.
And Where we Can Validate the access_token in server side (Web API).
I read lot but still very much confused.
Please help me.
Thanks!!
You don't need to worry about access token on server side. Access token on server side is parsed and validated by Katana middleware. If you need more details on how access token is created/used then search for DeserializeTicket and SerializeTicket methods in Katana sources, you will find that these methods are used in conjunction with Token to serialize/deserialize ClaimsIdentity which you have pased on client side(DummyMVC).
Anyway you are using SimpleAuthorizationServerProvider from Embedded AuthorizationServer Thinktecture project which is wrapper around OAuthAuthorizationServerProvider. Am I right? I belive you want to validate credentials. In your case you can override GrantResourceOwnerCredentials.
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
// validate user credentials (demo!)
// user credentials should be stored securely (salted, iterated, hashed yada)
if (context.UserName != context.Password)
{
context.Rejected();
return;
}
context.Validated();
}
Best will be if you look at Thinktecture examples.

Categories