Bearer token ignores asp.net user roles - asp.net-mvc

I have a asp.net mvc application that runs a hangfire task. This hangfire task retrieves client data from another asp.net mvc webserver application using a bearer token. The hangfire task sends a username and password to the webserver and gets a new bearer token in return every time its run using the code below.
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager,
OAuthDefaults.AuthenticationType);
ClaimsIdentity cookiesIdentity = await user.GenerateUserIdentityAsync(userManager,
CookieAuthenticationDefaults.AuthenticationType);
List<Claim> roles = oAuthIdentity.Claims.Where(c => c.Type == ClaimTypes.Role).ToList();
AuthenticationProperties properties = CreateProperties(user.UserName, Newtonsoft.Json.JsonConvert.SerializeObject(roles.Select(x => x.Value)));
AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
context.Validated(ticket);
context.Request.Context.Authentication.SignIn(cookiesIdentity);
}
public static AuthenticationProperties CreateProperties(string userName, string roles)
{
IDictionary<string, string> data = new Dictionary<string, string>
{
{ "userName", userName },
{ "roles", roles }
};
return new AuthenticationProperties(data);
}
This bearer token is then stored in a database. Once a new bearer token has been retrieved the application makes a http call to the webserver using the bearer token to retrieve the clients information.
The username and password / bearer token that is being sent is associated with a user on the webserver that has a role of 'WebserverUser'.
The problem is, Authorise(UserRole.WebserverUser)
is not currently doing anything. The http call is still being allowed even if I remove the 'WebserverUser' role from the user.
Is there a way I can make my application only allow the http call when the user is in the designated role?
[Route("GetClientsTable")]
[HttpGet, Authorise(UserRole.WebserverUser)]
[ResponseType(typeof(Byte[]))]
public IHttpActionResult GetClientsTable()
{
//Getting clients here..
return Ok(Clients);
}

Related

Dissecting ASP.NET MVC Identity for OAuth Bearer Authentication

I'm learning how to put the Asp.Net MVC Identity 2.0 to work.
I have this code that works for OAuth Bearer
[HttpGet]
[ActionName("Authenticate")]
[AllowAnonymous]
public String Authenticate(string user, string password)
{
if (string.IsNullOrEmpty(user) || string.IsNullOrEmpty(password))
{
return "Failed";
}
var userIdentity = UserManager.FindAsync(user, password).Result;
if (userIdentity != null)
{
if (User.Identity.IsAuthenticated)
{
return "Already authenticated!";
}
var identity = new ClaimsIdentity(Startup.OAuthBearerOptions.AuthenticationType);
identity.AddClaim(new Claim(ClaimTypes.Name, user));
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, userIdentity.Id));
AuthenticationTicket ticket = new AuthenticationTicket(identity, new AuthenticationProperties());
var currentUtc = new SystemClock().UtcNow;
ticket.Properties.IssuedUtc = currentUtc;
ticket.Properties.ExpiresUtc = currentUtc.Add(TimeSpan.FromMinutes(1));
string AccessToken = Startup.OAuthBearerOptions.AccessTokenFormat.Protect(ticket);
return AccessToken;
}
return "Failed in the end";
}
Here is the code for Startup.Auth.cs
//This will used the HTTP header Authorization: "Bearer 1234123412341234asdfasdfasdfasdf"
OAuthBearerOptions = new OAuthBearerAuthenticationOptions();
app.UseOAuthBearerAuthentication(OAuthBearerOptions);
I have looked at the source code for ClaimsIdentity and AuthenticationTicket and I don't see how the ticket is registered for the identity.
My question is how did this ticket get registered with the Owin pipeline?
My aim is to revoke this ticket if possible.
Thanks in advance.
First off, here is a great tutorial on ASP.NET Identity 2 by Taiseer Joudeh.
This is the line that adds Bearer token processing to an OWIN application pipeline.
app.UseOAuthBearerAuthentication(OAuthBearerOptions);
Also, did you write the authorization provider yourself? My startup code looks more like this:
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
PublicClientId = "self";
OAuthServerOptions = new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/Token"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(1440), //TODO: change to smaller value in production, 15 minutes maybe
Provider = new SimpleAuthorizationServerProvider(PublicClientId),
RefreshTokenProvider = new SimpleRefreshTokenProvider()
};
app.UseOAuthAuthorizationServer(OAuthServerOptions);
OAuthBearerOptions = new OAuthBearerAuthenticationOptions();
app.UseOAuthBearerAuthentication(OAuthBearerOptions);
My SimpleAuthorizationServerProvider then has a Grant method like this:
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var allowedOrigin = context.OwinContext.Get<string>("as:clientAllowedOrigin") ?? "*";
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin });
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
ApplicationUser user = await userManager.FindAsync(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(ClaimTypes.NameIdentifier, user.Id.ToString()));
identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
identity.AddClaim(new Claim("sub", context.UserName));
foreach (var role in userManager.GetRoles(user.Id))
{
identity.AddClaim(new Claim(ClaimTypes.Role, role));
}
var props = new AuthenticationProperties(new Dictionary<string, string>
{
{"as:client_id", context.ClientId ?? string.Empty}
});
var ticket = new AuthenticationTicket(identity, props);
context.Validated(ticket);
}
Just about all of this was based on the tutorial mentioned above. Hope it helps.
Update
There is no standard way to revoke a token according to Taiseer on this page.
Revoking access from authenticated users: Once the user obtains long lived access token he’ll be able to access the server resources
as long as his access token is not expired, there is no standard way
to revoke access tokens unless the Authorization Server implements
custom logic which forces you to store generated access token in
database and do database checks with each request. But with refresh
tokens, a system admin can revoke access by simply deleting the
refresh token identifier from the database so once the system requests
new access token using the deleted refresh token, the Authorization
Server will reject this request because the refresh token is no longer
available (we’ll come into this with more details).
However, here is an interesting approach that may accomplish what you need. It will just take a bit of custom implementation.

How to store bearer tokens when MVC and Web API are in different projects

Situation:
I have a Web API 2 project which acts as an Authorization server (/token endpoint) and a resource server. I am using the template that comes out of box with ASP.Net Web API minus any MVC reference.
The Start.Auth is configured as below:
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context and user manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Configure the application for OAuth based flow
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
// In production mode set AllowInsecureHttp = false
AllowInsecureHttp = true
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
var facebookAuthenticationOptions = new FacebookAuthenticationOptions()
{
AppId = ConfigurationManager.AppSettings["Test_Facebook_AppId"],
AppSecret = ConfigurationManager.AppSettings["Test_Facebook_AppSecret"],
//SendAppSecretProof = true,
Provider = new FacebookAuthenticationProvider
{
OnAuthenticated = (context) =>
{
context.Identity.AddClaim(new System.Security.Claims.Claim("FacebookAccessToken", context.AccessToken));
return Task.FromResult(0);
}
}
};
facebookAuthenticationOptions.Scope.Add("email user_about_me user_location");
app.UseFacebookAuthentication(facebookAuthenticationOptions);
}
The MVC 5 Client (different Project) uses the Web API app for authorization and data. Below is the code to retrieve the Bearer token in case of Username/Password store:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
model.ExternalProviders = await GetExternalLogins(returnUrl);
return View(model);
}
var client = Client.GetClient();
var response = await client.PostAsync("Token",
new StringContent(string.Format("grant_type=password&username={0}&password={1}", model.Email, model.Password), Encoding.UTF8));
if (response.IsSuccessStatusCode)
{
return RedirectToLocal(returnUrl);
}
return View();
}
Problem
I could retrieve the Bearer token and then add it to the Authorization Header for subsequent calls. I think that would be ok in case of an Angular App or a SPA. But I think there should be something in MVC that handles it for me, like automatically store it in a cookie and send the cookie on subsequent requests. I have searched around quite a lot and there are posts which hint towards this (Registering Web API 2 external logins from multiple API clients with OWIN Identity) but I haven't been able to figure out what to do after I get a token.
Do I need to add something in the MVC app Startup.Auth?
Ideally, I need the functionality which the AccountController in ASP.Net Template (MVC + Web API) gives out of box (Logins, Register, External logins, forget password etc etc...) but with the MVC and Web API in different projects.
Is there a template or a git repo which has this boiler plate code?
Thanks in advance!
Update
Incorporating #FrancisDucharme suggestions, below is the code for GrantResourceOwnerCredentials().
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager,
OAuthDefaults.AuthenticationType);
ClaimsIdentity cookiesIdentity = await user.GenerateUserIdentityAsync(userManager,
CookieAuthenticationDefaults.AuthenticationType);
AuthenticationProperties properties = CreateProperties(user.UserName);
AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
//Add a response cookie...
context.Response.Cookies.Append("Token", context.Options.AccessTokenFormat.Protect(ticket));
context.Validated(ticket);
context.Request.Context.Authentication.SignIn(cookiesIdentity);
}
But I can't still seem to get that Cookie or figure out what to do next.
Restating Questions:
What would be the correct way to authenticate, authorize and call Web API methods (Auth and Resource server) from an MVC client?
Is there boilerplate code or template for AccountController which does the basic plumbing (Login, register - internal/external, forgot password etc.)?
You could have your Startup class return a response cookie that the client will then return on all subsequent requests, here's an example. I would do it in GrantResourceOwnerCredentials.
public class AuthorizationServerProvider : OAuthAuthorizationServerProvider
{
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
//your authentication logic here, if it fails, do this...
//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"));
AuthenticationTicket ticket = new AuthenticationTicket(identity);
//Add a response cookie...
context.Response.Cookies.Append("Token", context.Options.AccessTokenFormat.Protect(ticket));
context.Validated(ticket);
}
The Startup class:
public partial class Startup
{
public static OAuthBearerAuthenticationOptions OAuthBearerOptions { get; private set; }
public Startup()
{
OAuthBearerOptions = new OAuthBearerAuthenticationOptions();
}
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
ConfigureOAuth(app);
//I use CORS in my projects....
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
WebApiConfig.Register(config);
}
public void ConfigureOAuth(IAppBuilder app)
{
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true, //I have this here for testing purpose, production should always only accept HTTPS encrypted traffic.
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
Provider = new AuthorizationServerProvider()
};
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(OAuthBearerOptions);
}
}
That assumes the client has cookies enabled, of course.
Then, modify your MVC headers to add the Authorization header to all requests as such.
In the ActionFilterAttribute, fetch your cookie value (Token) and add the header.
Instead of storing in session, I have added it to the the DefaultRequestHeaders as shown below so I don't need to add this in every call I make to Web API.
public async Task AuthenticateUser(string username, string password)
{
var data = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("grant_type", "password"),
new KeyValuePair<string, string>("username", username),
new KeyValuePair<string, string>("password", password)
});
using (HttpResponseMessage response = await APIClient.PostAsync("/Token", data))
{
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsAsync<AuthenticatedUser>();
APIClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.Access_Token);
}
else
{
throw new Exception(response.ReasonPhrase);
}
}
}

MVC 5 with forms authentication and interacting with Bearer token web api back end

I have a mvc 5 app that uses forms authentication but the real Authentication of user happens using bearer token in web api . I'm adding token details in the cookie so the website is always authenticated. MVC and Web api are in same project. Web api hosted using Owin.
here is my code snippet.
startup.cs
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
//Configure authorization
ConfigureOAuth(app);
//register WebAPI
app.UseWebApi(ConfigureWebApiRoutes());
}
}
startup.auth.cs
// Enable the application to use a cookie to store information for the signed in user
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Login/Login"),
CookieHttpOnly = true,
//AuthenticationMode = AuthenticationMode.Passive,
CookieName = "YetAnotherTodo.WebApi.Auth",
//#if DEBUG
// CookieSecure = CookieSecureOption.Never
//#endif
});
// Use a cookie to temporarily store information about a user logging in with a third party login provider
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
OAuthBearerOptions = new OAuthBearerAuthenticationOptions();
// using OAuth authentication server as authentication middle ware and Token Generation
app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new SimpleAuthorizationServerProvider(),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
#if DEBUG
AllowInsecureHttp = true
#endif
});
app.UseOAuthBearerAuthentication(OAuthBearerOptions);
code in MVC Login Controller
[AllowAnonymous]
[HttpPost]
public async Task<ActionResult> Login(LoginViewModel model, string redirectUrl = null)
{
if (!ModelState.IsValid) return View(model);
try
{
if (string.IsNullOrWhiteSpace(redirectUrl))
{
redirectUrl = "~/Home";
}
var result = await WebApiService.Instance.AuthenticateAsync<LogInResult>(model.UserName, model.Password);
//Let's keep the user authenticated in the MVC webapp.
//By using the AccessToken, we can use User.Identity.Name in the MVC controllers to make API calls.
FormsAuthentication.SetAuthCookie(result.AccessToken, model.RememberMe);
//Create an AuthenticationTicket to generate a cookie used to authenticate against Web API.
//But before we can do that, we need a ClaimsIdentity that can be authenticated in Web API.
var claims = new[]
{
new Claim(ClaimTypes.Name, model.UserName),
//Name is the default name claim type, and UserName is the one known also in Web API.
new Claim(ClaimTypes.NameIdentifier, model.UserName)
//If you want to use User.Identity.GetUserId in Web API, you need a NameIdentifier claim.
};
//Generate a new ClaimsIdentity, using the DefaultAuthenticationTypes.ApplicationCookie authenticationType.
//This also matches what we've set up in Web API.
var claimsIdentity = new ClaimsIdentity(claims,DefaultAuthenticationTypes.ApplicationCookie);
var authProperties = new AuthenticationProperties
{
ExpiresUtc = result.Expires,
IsPersistent = model.RememberMe,
IssuedUtc = result.Issued,
RedirectUri = redirectUrl
};
var authTicket = new AuthenticationTicket(claimsIdentity, authProperties);
//And now it's time to generate the cookie data. This is using the same code that is being used by the CookieAuthenticationMiddleware class in OWIN.
byte[] userData = DataSerializers.Ticket.Serialize(authTicket);
//Protect this user data and add the extra properties. These need to be the same as in Web API!
//byte[] protectedData = MachineKey.Protect(userData, new[] { "Microsoft.Owin.Security.Cookies.CookieAuthenticationMiddleware", DefaultAuthenticationTypes.ApplicationCookie, "v1" });
//base64-encode this data.
string protectedText = TextEncodings.Base64Url.Encode(userData);
//And now, we have the cookie.
Response.SetCookie(new HttpCookie("YetAnotherTodo.WebApi.Auth")
{
HttpOnly = true,
Expires = result.Expires.UtcDateTime,
Value = protectedText
});
Code in my provider that generates token
AuthenticationTicket ticket;
var cookiesIdentity = GenerateCookiesIdentity(context, user, out ticket);
context.Validated(ticket);
context.Request.Context.Authentication.SignIn(cookiesIdentity);
I was able to login and able to get ticket from token server but on subsequent request or redirect to home page after logging in , I'm still getting 401 error.
This is kinda combinations of these two blogs/tutorials : Blog 1 and Blog 2

Claims GetUserId is null

I hope you're all great, this time I'm here to ask an issue that I can't figure it out and it's about Identity, the thing is I want to get de User Id from the Claims principal or whereever it is, right now the only thing that I have is
var principal = ClaimsPrincipal.Current;
var id1 = principal.Claims.FirstOrDefault(c => c.ValueType == ClaimTypes.NameIdentifier);
but when I try to get the UserId and I go to the information inside the claims I can't find the value even if I saved it in the AuthorizationTicket at login.
I'm working with MVC template and Web api service My service is hosted in IIS and with it I manage the authentication with an accountcontroller via Token
this is my AuthenticationProperties
public static AuthenticationProperties CreateProperties(string userName, string userid)
{
IDictionary<string, string> data = new Dictionary<string, string> { { "userName", userName }, { "userId", userid } };
return new AuthenticationProperties(data);
}
and my GrantResourceOwnerCredentiales
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
//var userManager = DependencyResolver.Current.GetService<ApplicationUserManager>();
AppJobSeeker user = await userManager.FindAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager, OAuthDefaults.AuthenticationType);
ClaimsIdentity cookiesIdentity = await user.GenerateUserIdentityAsync(userManager, CookieAuthenticationDefaults.AuthenticationType);
AuthenticationProperties properties = CreateProperties(user.UserName, user.Id);
AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
context.Validated(ticket);
context.Request.Context.Authentication.SignIn(cookiesIdentity);...
And I have a method which creates a AuthenticationTicket and it receive the UserName and the UserId as well
private void CreateTicket(SignInResult result, SignInModel model, string returnUrl)
{
//Let's keep the user authenticated in the MVC webapp.
//By using the AccessToken, we can use User.Identity.Name in the MVC controllers to make API calls.
FormsAuthentication.SetAuthCookie(result.AccessToken, model.RememberMe);
//Create an AuthenticationTicket to generate a cookie used to authenticate against Web API.
//But before we can do that, we need a ClaimsIdentity that can be authenticated in Web API.
var claims = new[]
{
new Claim(ClaimTypes.Name, result.UserName), //Name is the default name claim type, and UserName is the one known also in Web API.
new Claim(ClaimTypes.NameIdentifier, result.UserId), //If you want to use User.Identity.GetUserId in Web API, you need a NameIdentifier claim.
};
//Generate a new ClaimsIdentity, using the DefaultAuthenticationTypes.ApplicationCookie authenticationType.
//This also matches what we've set up in Web API.
var authTicket = new AuthenticationTicket(new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie), new AuthenticationProperties
{
ExpiresUtc = result.Expires,
IsPersistent = model.RememberMe,
IssuedUtc = result.Issued,
RedirectUri = returnUrl
});
...
Everithing looks fine when I do the login but when a I go to another controller I can't retreive the UserId
Have you added the [Authorize] attribute to your controller?
[Authorize]
public class AuthorizeController : ApiController
{
public Task<IHttpActionResult> GetUserId()
{
return Ok(HttpContext.Current.User.Identity.GetUserId());
}
}

Bearer Token Authentication and Password Change

Now i am in learning stage of owin bearer token authentication in Web API. The code is implemented with token and cookie based authentication. The code is
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
try
{
using (UserManager<ApplicationUser> userManager = userManagerFactory())
{
ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);
if (user == null || user.IsDeleted)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
ClaimsIdentity oAuthIdentity = await userManager.CreateIdentityAsync(user,
context.Options.AuthenticationType);
ClaimsIdentity cookiesIdentity = await userManager.CreateIdentityAsync(user,
CookieAuthenticationDefaults.AuthenticationType);
var roleName = await GetRoleName(user.Roles.First().RoleId);
AuthenticationProperties properties = CreateProperties(user.UserName, roleName);
AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
context.Validated(ticket);
context.Request.Context.Authentication.SignIn(cookiesIdentity);
}
}
catch (Exception ex)
{
throw ex;
}
}
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
// Resource owner password credentials does not provide a client ID.
if (context.ClientId == null)
{
context.Validated();
}
return Task.FromResult<object>(null);
}
public override Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context)
{
if (context.ClientId == _publicClientId)
{
Uri expectedRootUri = new Uri(context.Request.Uri, "/");
if (expectedRootUri.AbsoluteUri == context.RedirectUri)
{
context.Validated();
}
}
return Task.FromResult<object>(null);
}
The code is implemented by colleague and i have some doubts.
Token authentication is based on the generated token. I generated a token for my user, whose role is 'Admin'. Now i can access restricted action as the user has 'Admin' role. But after that i changed the role to 'User' for the same old user. Now with the same old token i can access the resource even he is not in 'Admin' now. Actually i read some articles that this is implemented with extra custom logic. its ok
Now i changed the user password to some other password. Now itself, i can access the resource with same old token. I think this is not good even i create short lived tokens also.
Anyone please guide to arrest this or i missed anything? Which method actually call when i call an action with 'Authorization' header
Well there is no “direct” way to revoke granted access tokens or do “logoff”. if the user has the token then he can access the secured server resources until the token is expired. The indirectway is to store token_id for each token granted to the user in a database and do DB checks with each call which is something I do not recommend.
So in some situations it is better to use the refresh tokens along with the access token. So you issue short lived access token (15) mins and you use the refresh token to obtain new access tokens. The nice thing here that refresh tokens can be revoked from the backend system so there is control on them.
Check my post on how to enable OAuth refresh tokens in ASP.NET Web API

Resources