WebApi 2 Oauth2 Android client - asp.net-mvc

I want my android app to communicate with an Asp.net WebApi2 secured by Oauth2. All samples I've found only show how it is done for websites.
I'm able to get an access token from the "/token" endpoint and I add this token to the http header in the Autorization attribute. However, I always get: "Authorization has been denied for this request."
My Startup Auth looks like:
public partial class Startup
{
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
public static string PublicClientId { get; private set; }
public void ConfigureAuth(IAppBuilder app)
{
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new SimmpleApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
app.UseOAuthAuthorizationServer(OAuthOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
}
My SimmpleApplicationOAuthProvider looks like:
public class SimmpleApplicationOAuthProvider : OAuthAuthorizationServerProvider
{
private readonly string _publicClientId;
public SimmpleApplicationOAuthProvider(string publicClientId)
{
if (publicClientId == null)
{
throw new ArgumentNullException("publicClientId");
}
_publicClientId = publicClientId;
}
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;
}
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim("sub", context.UserName));
identity.AddClaim(new Claim("role", "user"));
context.Validated(identity);
}
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
}
}
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
// Enforce HTTPS
//config.Filters.Add(new LocalAccountsApp.Filters.RequireHttpsAttribute());
}
}
I'm using Wireshark to analyse network traffic. This is my GET request:
GET /LocalAccountsApp/api/values HTTP/1.1
Content-Type: application/json; charset=utf-8
Authorization: Bearer SXFPTU5Sb2JVZWh6M3ZIcEtMRzdiMVVZd3hleTBWbHI2eFZtR2xFSFJQT...
User-Agent: Dalvik/2.1.0 (Linux; U; Android 5.0; LG-D855 Build/LRX21R.A1421650137)
Host: 192.168.1.7
Connection: Keep-Alive
Accept-Encoding: gzip
I placed a breakpoint in "GrantResourceOwnerCredentials" and it is hit both times (for /token and for /api/values). So where is my call rejected?

OAuthBearerAuthenticationOptions
is double if you remove one then have a look

Related

How to setup MVC requests to use Oauth 2.0 access token?

I am working on an Asp.net Web API + MVC project. While creating the project, I selected 'Individual User Accounts' option for authentication. After login, the provider issues access token and I use this token in HTTP header of ajax calls and it works fine with Ajax calls. I also have MVC actions which are used to navigate to different pages. These actions are protected using [Authorize] attribute of System.web.MVC. While navigating to these actions authorization fails and I am redirected to login page. How do I configure Oauth 2.0 access token to be used in non ajax requests (MVC requests) also.
Startup.Auth.cs:
public partial class Startup
{
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
public static string PublicClientId { get; private set; }
// For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
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 {
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Home/Login"),
LogoutPath = new PathString("/Account/LogOff"),
ExpireTimeSpan = TimeSpan.FromHours(1.0),
});
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("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true // dont use this for production,
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
}
WebApiConfig.cs:
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
ApplicationOAuthProvider.cs:
public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
{
private readonly string _publicClientId;
public ApplicationOAuthProvider(string publicClientId)
{
if (publicClientId == null)
{
throw new ArgumentNullException("publicClientId");
}
_publicClientId = publicClientId;
}
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);
context.Validated(ticket);
context.Request.Context.Authentication.SignIn(cookiesIdentity);
}
public override Task TokenEndpoint(OAuthTokenEndpointContext context)
{
foreach (KeyValuePair<string, string> property in context.Properties.Dictionary)
{
context.AdditionalResponseParameters.Add(property.Key, property.Value);
}
return Task.FromResult<object>(null);
}
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);
}
public static AuthenticationProperties CreateProperties(string userName)
{
IDictionary<string, string> data = new Dictionary<string, string>
{
{ "userName", userName }
};
return new AuthenticationProperties(data);
}
}
ASP.Net MVC is a server side web app technology and [Authorize] actions expect to receive a cookie rather than checking for a token.
Not sure if this is overridable and in this type of solution you often end up having to deal with an ugly mix of cookies / tokens / server side code / client side code.
A more modern / cleaner separation is to develop a single page app + REST API instead. Code tends to be simpler and it feels like a better fit for the requirements you mention.
To see what I mean, maybe have a quick browse of the UI code in this sample:
https://github.com/gary-archer/oauth.websample1
The repo links to some blog posts if it's an option you're interested in.

How i can store bearer tokens on server-side and after validate how to delete on logout in Web API 2?

I am creating web api project, by default it have account controller in which i found Register,Logout and other api's .
Using Web API 2, OAuth and OWIN
By /token i generated bearer token and his expiry time which is storing in OWIN Cookie authentication.
My Question is : -
how i can delete this token when user logout because after using logout service i can still call list data which is decorated with [Authorize]
can i store it in database and validate it, delete it when user logout
Logout code is below
// POST api/Account/Logout
[Route("Logout")]
public IHttpActionResult Logout()
{
// Authentication.SignOut(CookieAuthenticationDefaults.AuthenticationType);
return ok();
}
and my /token code is 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("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
// In production mode set AllowInsecureHttp = false
AllowInsecureHttp = true
};
}
You cannot delete the token in server, however you can forget the token in client side.
Or you can create refresh token service
Just create the class
public class SimpleRefreshTokenProvider : IAuthenticationTokenProvider {
private static ConcurrentDictionary<string, AuthenticationTicket> _refreshTokens = new ConcurrentDictionary<string, AuthenticationTicket>();
public async Task CreateAsync(AuthenticationTokenCreateContext context) {
var guid = Guid.NewGuid().ToString();
_refreshTokens.TryAdd(guid, context.Ticket);
context.SetToken(guid);
}
public async Task ReceiveAsync(AuthenticationTokenReceiveContext context) {
AuthenticationTicket ticket;
if (_refreshTokens.TryRemove(context.Token, out ticket)) {
context.SetTicket(ticket);
}
}
}
Register it in
static Startup() {
OAuthOptions = new OAuthAuthorizationServerOptions {
TokenEndpointPath = new PathString("/api/Login"),
Provider = new OAuthProvider(),
RefreshTokenProvider = new SimpleRefreshTokenProvider(),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(5),
AllowInsecureHttp = true,
};
}
Override OAuthAuthorizationServerProvider
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) {
if (context.TryGetBasicCredentials(out clientId, out clientSecret)) {
if (clientSecret == "secret") {
context.OwinContext.Set<string>("as:client_id", clientId);
context.Validated();
}
}
return Task.FromResult<object>(null);
}
and your service request should be look like this
Authorization: Basic Y2xpZW50MTpzZWNyZXQ=
Content-Type: application/x-www-form-urlencoded
username=care%40agentExperience.com&password=test&client_id=client1&clientSecret=secret&grant_type=refresh_token

storing JWT token in cookie in MVC 5

I wanted to make JWT auth in my MVC app. I make Authorization web service in Web API which returns token correctly. After that Im trying to store token in cookie.
[HttpPost]
public async Task<ActionResult> Login(LoginDto loginDto)
{
var token = await loginService.GetToken(loginDto);
if (!string.IsNullOrEmpty(token))
{
var cookie = new System.Web.HttpCookie("token", token)
{
HttpOnly = true
};
Response.Cookies.Add(cookie);
return RedirectToAction("Index", "Product");
}
return View("LoginFailed");
}
But now I wanted to add this token to headers for every request. So I decided action filters would be best for achieve this.
public class CustomActionFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var token = filterContext.HttpContext.Request.Cookies.Get("token");
if (token != null)
filterContext.HttpContext.Request.Headers.Add("Authorization", $"Bearer {token}");
base.OnActionExecuting(filterContext);
}
}
Startup
public class Startup
{
public void Configuration(IAppBuilder app)
{
AutofacConfig.Configure();
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
ConfigureOAuth(app);
}
public void ConfigureOAuth(IAppBuilder app)
{
var issuer = System.Configuration.ConfigurationManager.AppSettings["issuer"];
var audience = System.Configuration.ConfigurationManager.AppSettings["appId"];
var secret = TextEncodings.Base64Url.Decode(System.Configuration.ConfigurationManager.AppSettings["secret"]);
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
AllowedAudiences = new[] { audience },
IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
{
new SymmetricKeyIssuerSecurityTokenProvider(issuer, secret)
},
});
}
}
And then I just marked controller which authorize attribute. It works fine when I called it with POSTMAN.
But action filters in MVC are fired always after authorization filter. So I have questions:
How to add token from cookie to every request ? Is it good practice? If not what I should do?
How about csrf attacks and others ? Is AntiForgeryTokenAttr will do the work? What about ajax calls then?
Additional Information
This is how login service looks like. Its just making call to auth endpoint.
public class LoginService : ILoginService
{
public async Task<string> GetToken(LoginDto loginDto)
{
var tokenIssuer = ConfigurationManager.AppSettings["issuer"];
using (var httpClient = new HttpClient {BaseAddress = new Uri($"{tokenIssuer}/oauth2/token")})
{
using (var response = await httpClient.PostAsync(httpClient.BaseAddress, new FormUrlEncodedContent(
new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("username", loginDto.Username),
new KeyValuePair<string, string>("password", loginDto.Password),
new KeyValuePair<string, string>("grant_type", "password"),
new KeyValuePair<string, string>("client_id", ConfigurationManager.AppSettings["appId"])
})))
{
var contents = await response.Content.ReadAsStringAsync();
if (response.StatusCode == HttpStatusCode.OK)
{
var deserializedResponse =
new JavaScriptSerializer().Deserialize<Dictionary<string, string>>(contents);
var token = deserializedResponse["access_token"];
return token;
}
}
return null;
}
}
}
I found a solution. I just make custom OAuthBearerAuthenticationProvider provider and inside this class Im retrieve token from cookie and then assign this to context.Token
public class MvcJwtAuthProvider : OAuthBearerAuthenticationProvider
{
public override Task RequestToken(OAuthRequestTokenContext context)
{
var token = context.Request.Cookies.SingleOrDefault(x => x.Key == "token").Value;
context.Token = token;
return base.RequestToken(context);
}
}
And then inside startup.cs
public class Startup
{
public void Configuration(IAppBuilder app)
{
AutofacConfig.Configure();
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
ConfigureOAuth(app);
}
public void ConfigureOAuth(IAppBuilder app)
{
var issuer = System.Configuration.ConfigurationManager.AppSettings["issuer"];
var audience = System.Configuration.ConfigurationManager.AppSettings["appId"];
var secret = TextEncodings.Base64Url.Decode(System.Configuration.ConfigurationManager.AppSettings["secret"]);
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
AllowedAudiences = new[] { audience },
IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
{
new SymmetricKeyIssuerSecurityTokenProvider(issuer, secret)
},
Provider = new MvcJwtAuthProvider() // override custom auth
});
}
}

OAuth token bearer extra user information

I am using Web API secured with OAuth Bearer token. When getting the token I want to send extra information to the user, so I tried the following as per this thread:
CustomOAuthProvider.cs:
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
// Other stuff, cut off for brevity
var user = await userManager.FindAsync(context.UserName, context.Password);
ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager, "JWT");
oAuthIdentity.AddClaims(ExtendedClaimsProvider.GetClaims(user));
oAuthIdentity.AddClaims(RolesFromClaims.CreateRolesBasedOnClaims(oAuthIdentity));
var ticket = new AuthenticationTicket(oAuthIdentity, this.CreateProperties(user.UserName, oAuthIdentity));
context.Validated(ticket);
}
private AuthenticationProperties CreateProperties(string userName, ClaimsIdentity oAuthIdentity)
{
var data = new Dictionary<string, string>
{
{ "username", userName },
{ "roles", JsonConvert.SerializeObject(oAuthIdentity.Claims.Where(c=> c.Type == ClaimTypes.Role).Select(c => c.Value).ToArray()) }
};
return new AuthenticationProperties(data);
}
But the returned object is always as following:
{
access_token: "theTokenHash"
expires_in: 86399
token_type: "bearer"
}
This is my Startup.cs:
public void Configuration(IAppBuilder app)
{
// AutoMapper
AutoMapperConfig.RegisterMappings();
var httpConfig = new HttpConfiguration();
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
ConfigureOAuthTokenGeneration(app);
ConfigureOAuthTokenConsumption(app);
ConfigureWebApi(httpConfig);
WebApiConfig.Register(httpConfig);
AutofacConfig.Register(httpConfig);
app.UseWebApi(httpConfig);
httpConfig.EnsureInitialized();
}
private void ConfigureOAuthTokenGeneration(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);
app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
var OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
//For Dev enviroment only (on production should be AllowInsecureHttp = false)
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/oauth/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new CustomOAuthProvider(),
AccessTokenFormat = new CustomJwtFormat("http://localhost:59822")
};
// OAuth 2.0 Bearer Access Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
What am I doing wrong here?
Wow never mind, I dug into the full example given in the answer of the link. It seems that adding the extra fields isn't enough. You still have to add the parameters to the context yourself by overriding the TokenEndpoint function:
public override Task TokenEndpoint(OAuthTokenEndpointContext context)
{
foreach (KeyValuePair<string, string> property in context.Properties.Dictionary)
{
context.AdditionalResponseParameters.Add(property.Key, property.Value);
}
return Task.FromResult<object>(null);
}

Web Api with Owin with JWT always fails to authorize request

I have followed the tutorials up till this point in the series. I am using one project in the solution that acts as both the token issuing authority as well as the resource server.
The JWT is generated using the endpoint mentioned in the startup class and I validated it on jwt.io as well. However when I pass this JWT using Postman on Chrome to the resource API end point secured with an Authorize attribute, I always find it returning
{
"message": "Authorization has been denied for this request." }
The other api method as in the api controller class below works when called thru Postman on Chrome.
I have used the latest versions of all dlls required from the nuget console
Code in the startup class
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
ConfigureOAuthTokenGeneration(app);
ConfigureOAuthTokenConsumption(app);
WebApiConfig.Register(config);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
}
private void ConfigureOAuthTokenGeneration(IAppBuilder app)
{
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
//For Dev enviroment only (on production should be AllowInsecureHttp = false)
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/oauth/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new CustomOAuthProvider(),
AccessTokenFormat = new CustomJwtFormat(ConfigurationManager.AppSettings["Issuer"]),
};
// OAuth 2.0 Bearer Access Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
}
private void ConfigureOAuthTokenConsumption(IAppBuilder app)
{
string issuer = ConfigurationManager.AppSettings["Issuer"];
string audienceId = ConfigurationManager.AppSettings["AudienceId"];
byte[] audienceSecret = TextEncodings.Base64Url.Decode(ConfigurationManager.AppSettings["AudienceSecret"]);
// Api controllers with an [Authorize] attribute will be validated with JWT
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
AllowedAudiences = new[] { audienceId },
IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
{
new SymmetricKeyIssuerSecurityTokenProvider(issuer, audienceSecret)
}
});
}
Code in the Custom OAuthProvider
public class CustomOAuthProvider : OAuthAuthorizationServerProvider
{
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
return Task.FromResult<object>(null);
}
public override Task MatchEndpoint(OAuthMatchEndpointContext context)
{
//avoid pre-flight calls
if (context.OwinContext.Request.Method == "OPTIONS" && context.IsTokenEndpoint)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Methods", new[] { "POST" });
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Headers", new[] { "accept", "authorization", "content-type" });
context.OwinContext.Response.StatusCode = 200;
context.RequestCompleted();
return Task.FromResult<object>(null);
}
return base.MatchEndpoint(context);
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
//setting up claims in the constructor of class UserDetails
UserDetails user = new UserDetails();
user.UserName = context.UserName;
user.FirstName = "Dummy First";
user.LastName = "Dummy Last";
ClaimsIdentity identity = new ClaimsIdentity("JWT-BearerAuth-Test");
identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
foreach (string claim in user.Claims)
{
identity.AddClaim(new Claim(ClaimTypes.Role, claim));
}
var ticket = new AuthenticationTicket(identity, null);
context.Validated(ticket);
}
}
The custom JWT class
public class CustomJwtFormat : ISecureDataFormat<AuthenticationTicket>
{
private readonly string _issuer = string.Empty;
public CustomJwtFormat(string issuer)
{
_issuer = issuer;
}
public string Protect(AuthenticationTicket data)
{
if (data == null)
{
throw new ArgumentNullException("data");
}
string audienceId = ConfigurationManager.AppSettings["AudienceId"];
string symmetricKeyAsBase64 = ConfigurationManager.AppSettings["AudienceSecret"];
var keyByteArray = TextEncodings.Base64Url.Decode(symmetricKeyAsBase64);
var signingKey = new HmacSigningCredentials(keyByteArray);
var issued = data.Properties.IssuedUtc;
var expires = data.Properties.ExpiresUtc;
var token = new JwtSecurityToken(_issuer, audienceId, data.Identity.Claims, issued.Value.UtcDateTime, expires.Value.UtcDateTime, signingKey);
var handler = new JwtSecurityTokenHandler();
var jwt = handler.WriteToken(token);
return jwt;
}
}
The Resource server's Api controller
public class AdminController : ApiController
{
//This call works
public IHttpActionResult ReadData(string id)
{
return Ok("ID sent in:" + id);
}
//[Authorize(Roles="EditRecord")] //doesnt work
[Authorize] //doesnt work either
public IHttpActionResult EditData(string id)
{
return Ok("Edited ID:" + id);
}
}
My environment is VS2013 with Framework 4.5 using OAuth2 with Web Api 2. Please excuse the long post.
You need to make sure that values for issuer, audienceId, and audienceSecret used in method "ConfigureOAuthTokenConsumption" are the same values used when you generated the JWT token, take care of trailing slashes "/".
This is the only thing comes to my mind right now.

Resources