How to implement authorize web api using OAuth clientID and secret - c#

I want to implement OAuth authorization on web api. I am generating JWT token using microsoft graph api
public Token GetToken()
{
try
{
string baseAddress = "https://login.windows.net/<tenantid>/oauth2/token?api-version=1.0";
var client = new HttpClient();
var form = new Dictionary<string, string>{
{
"grant_type",
"client_credentials"
},
{
"client_id",
"<clientid>"
},
{
"client_secret",
"<clientsecret>"
}
};
var tokenResponse = client.PostAsync(baseAddress, new FormUrlEncodedContent(form)).Result;
var token = tokenResponse.Content.ReadAsAsync<Token>(new[] { new JsonMediaTypeFormatter() }).Result;
return token;
}
catch (Exception exc)
{
return new Token();
}
}
I am getting back jwt token but my controller is not able to authorize this. My Startup.cs looks like this:
public void Configuration(IAppBuilder app)
{
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=316888
ConfigureAuth(app);
}
public void ConfigureAuth(IAppBuilder app)
{
var OAuthBearerOptions = new OAuthBearerAuthenticationOptions();
OAuthAuthorizationServerOptions oAuthServerOptions = new OAuthAuthorizationServerOptions()
{
TokenEndpointPath = new PathString("/oauth2/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(60), //token expiration time
Provider = new OAuthProvider(),
};
app.UseOAuthBearerAuthentication(OAuthBearerOptions);
app.UseOAuthAuthorizationServer(oAuthServerOptions);
}

Related

IdentityServer4 Resource owner password and Win auth: unauthorized

in the last few days I've been reading IdentityServer4 docs and putting together my sample server + sample client using Resource owner password. Now I'd like to add Windows authentication (will be done via Active Directory) in parallel, so the client app (not a web app but a desktop app) could either prompt the user for credentials or login using Windows authentication via Active Directory.
The documentation about Windows Authentication explains how to configure IIS or HTTP.Sys, but what I want is to:
user opens the app
the app use single sign on to post a request to the web api to request token and refresh token
the web api uses windows authentication to validate the identity of the user and returns the token
I've tried to follow this answer, but it doesn't work (It returns unauthorized).
web api: Startup.cs
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMvcCore()
.AddAuthorization()
.AddJsonFormatters();
services.AddAuthentication("Bearer")
.AddJwtBearer(options =>
{
// base-address of your identityserver
options.Authority = "http://localhost:5000";
options.RequireHttpsMetadata = false;
// name of the API resource
options.Audience = "api/user";
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddIdentityServer(options => { options.PublicOrigin = "http://localhost:5000"; options.MutualTls.Enabled = false; })
.AddExtensionGrantValidator<WinAuthGrantValidator>()
.AddDeveloperSigningCredential()
.AddTestUsers(Config.GetUsers())
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryClients(Config.GetClients())
.AddInMemoryIdentityResources(Config.GetIdentityResources());
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env,
ILogger<Startup> logger, IServer server)
{
app.Use(async (context, next) =>
{
context.Features.Get<IHttpMaxRequestBodySizeFeature>()
.MaxRequestBodySize = 10 * 1024;
var serverAddressesFeature =
app.ServerFeatures.Get<IServerAddressesFeature>();
var addresses = string.Join(", ", serverAddressesFeature?.Addresses);
logger.LogInformation($"Addresses: {addresses}");
await next.Invoke();
});
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
// Enable HTTPS Redirection Middleware when hosting the app securely.
//app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseMvc();
app.UseIdentityServer();
app.UseAuthentication();
}
}
internal static class Config
{
public static List<TestUser> GetUsers()
{
return new List<TestUser>
{
new TestUser
{
SubjectId = "1",
Username = "alice",
Password = "password"
},
new TestUser
{
SubjectId = "2",
Username = "bob",
Password = "password"
}
};
}
public static IEnumerable<Client> GetClients()
{
return new List<Client>
{
// other clients omitted...
// resource owner password grant client
new Client
{
ClientId = "ro.client",
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
ClientSecrets =
{
new Secret("secret".Sha256())
},
// AllowedScopes = { "api1" }
AllowedScopes = { "api/user" }
},
new Client
{
ClientId = "winauth",
AllowedGrantTypes = new List<string>{ "windows_auth" },
ClientSecrets =
{
new Secret("secret".Sha256())
},
// AllowedScopes = { "api1" }
AllowedScopes = { "api/user" }
}
};
}
internal static IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>
{
new ApiResource { Name = "api1",Scopes = new List<Scope> { new Scope { Name = "api1",
DisplayName = "Full access to API 2"} }, Enabled = true, ApiSecrets = new List<Secret>
{
new Secret("secret".Sha256())
}
},
new ApiResource { Name = "api/user",Scopes = new List<Scope> { new Scope { Name = "api/user",
DisplayName = "Full access to API 2"} }, Enabled = true, ApiSecrets = new List<Secret>
{
new Secret("secret".Sha256())
}
}};
}
public static List<IdentityResource> GetIdentityResources()
{
return new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile()
};
}
}
public class WinAuthGrantValidator : IExtensionGrantValidator
{
private readonly HttpContext httpContext;
public string GrantType => "windows_auth";
public WinAuthGrantValidator(IHttpContextAccessor httpContextAccessor)
{
httpContext = httpContextAccessor.HttpContext;
}
public async Task ValidateAsync(ExtensionGrantValidationContext context)
{
// see if windows auth has already been requested and succeeded
var result = await httpContext.AuthenticateAsync("Windows");
if (result?.Principal is WindowsPrincipal wp)
{
context.Result = new GrantValidationResult(wp.Identity.Name, GrantType, wp.Claims);
}
else
{
// trigger windows auth
await httpContext.ChallengeAsync("Windows");
context.Result = new GrantValidationResult { IsError = false, Error = null, Subject = null };
}
}
}
}
web API: Program.cs
public class Program
{
public static void Main(string[] args)
{
var isService = !(Debugger.IsAttached || args.Contains("--console"));
if (isService)
{
var pathToExe = Process.GetCurrentProcess().MainModule.FileName;
var pathToContentRoot = Path.GetDirectoryName(pathToExe);
Directory.SetCurrentDirectory(pathToContentRoot);
}
var builder = CreateWebHostBuilder(
args.Where(arg => arg != "--console").ToArray());
var host = builder.Build();
if (isService)
{
// To run the app without the CustomWebHostService change the
// next line to host.RunAsService();
host.RunAsCustomService();
}
else
{
host.Run();
}
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddEventLog();
})
.ConfigureAppConfiguration((context, config) =>
{
// Configure the app here.
})
.UseStartup<Startup>()
.UseHttpSys(options =>
{
options.AllowSynchronousIO = true;
options.Authentication.Schemes = Microsoft.AspNetCore.Server.HttpSys.AuthenticationSchemes.Kerberos | Microsoft.AspNetCore.Server.HttpSys.AuthenticationSchemes.NTLM;
options.Authentication.AllowAnonymous = true;
options.MaxConnections = null;
options.MaxRequestBodySize = 30000000;
options.UrlPrefixes.Add("http://localhost:5000");
});
}
web API UserController.cs
[Route("api/[controller]")]
[Authorize(AuthenticationSchemes = "Bearer")]
[ApiController]
public class UserController : ControllerBase
{
// GET api/user
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { User.Identity.Name, User.Identity.AuthenticationType };
}
}
client code:
using (var client = new HttpClient())
{
disco = await client.GetDiscoveryDocumentAsync(new DiscoveryDocumentRequest
{
Address = baseUrl,
Policy = { RequireHttps = false }
});
if (disco.IsError)
{
Console.WriteLine(disco.Error);
Console.ReadLine();
return;
}
var httpHandler = new HttpClientHandler
{
UseDefaultCredentials = true,
};
using (var client = new HttpClient())
{
// request token
TokenResponse tokenResponse = await client.RequestTokenAsync(new TokenRequest
{
GrantType = "windows_auth",
Address = disco.TokenEndpoint,
ClientId = "winauth",
ClientSecret = "secret"
});
if (tokenResponse.IsError)
{
Console.WriteLine(tokenResponse.Error);
Console.ReadLine();
return;
}
}
It returns unauthorized.
I found a solution to this: I need to configure a TestUser with SubjectId = MYDOMAIN\myusername then it worked.
The error was getting was overly confusing.

"Message": "Authorization has been denied for this request." OWIN middleware

I added Token based authentication to my OWIN middleware and can generate the token. But while using, the token for an API call with Authorize attribute I always get "Authorization has been denied for this request." It works fine though without Authorize attribute. Here is my startup.cs and controller method. Any thoughts , what is wrong?
startup.cs
public void Configuration(IAppBuilder app)
{
var issuer = ConfigurationManager.AppSettings["issuer"];
var secret = TextEncodings.Base64Url.Decode(ConfigurationManager.AppSettings["secret"]);
app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
{
AuthenticationType = DefaultAuthenticationTypes.ExternalBearer,
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
Provider = new SimpleAuthProvider(),
AccessTokenFormat = new JwtFormat(issuer)
});
app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ExternalBearer,
AuthenticationMode = AuthenticationMode.Active,
AllowedAudiences = new[] { "*" },
IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
{
new SymmetricKeyIssuerSecurityTokenProvider(issuer, secret)
}
});
container = BuildDI();
var config = new HttpConfiguration();
config.Formatters.XmlFormatter.UseXmlSerializer = true;
config.MapHttpAttributeRoutes();
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(DefaultAuthenticationTypes.ExternalBearer));
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
app.UseCors(CorsOptions.AllowAll);
app.UseSerilogRequestContext("RequestId");
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(config);
app.UseWebApi(config);
RegisterShutdownCallback(app, container);
}
public class SimpleAuthProvider: OAuthAuthorizationServerProvider
{
public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
if (context.UserName != context.Password)
{
context.SetError("invalid_grant", "The user name or password is incorrect");
context.Rejected();
return Task.FromResult<object>(null);
}
var ticket = new AuthenticationTicket(SetClaimsIdentity(context), new AuthenticationProperties());
context.Validated(ticket);
return Task.FromResult<object>(null);
}
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
return Task.FromResult<object>(null);
}
private static ClaimsIdentity SetClaimsIdentity(OAuthGrantResourceOwnerCredentialsContext context)
{
var identity = new ClaimsIdentity(DefaultAuthenticationTypes.ExternalBearer);
identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
return identity;
}
}
API Controller Method:
[HttpGet]
[Route("sampleroute")]
[Authorize]
public async Task<HttpResponseMessage> GetSamples(string search)
{
try
{
HttpResponseMessage response;
using (HttpClient client = new HttpClient(Common.CreateHttpClientHandler()))
{
response = await client.GetAsync("test url");
}
var result = response.Content.ReadAsStringAsync().Result;
Samples[] sampleArray = JsonConvert.DeserializeObject<Samples[]>(result);
var filteredSamples = sampleArray .ToList().Where(y => y.NY_SampleName.ToUpper().Contains(search.ToUpper())).Select(n=>n);
log.Information("<==========Ended==========>");
return Request.CreateResponse(HttpStatusCode.OK,filteredSamples);
}
catch (Exception ex)
{
log.Error($"Error occured while pulling the Samples: {ex.ToString()}");
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex.ToString());
}
}
It's probably a problem with the allowed audiences.
Here
app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions
{
...
AllowedAudiences = new[] { "*" },
...
}
you set the allowed audiences. The tokens audclaim will be checked against the list of AllowedAudiences. But you never add any audience to the token.
In our project I used a CustomJwtFormat based on the code shown in http://bitoftech.net/2014/10/27/json-web-token-asp-net-web-api-2-jwt-owin-authorization-server/
The token will be generated with a call to
var token = new JwtSecurityToken(_issuer, audienceId, data.Identity.Claims, issued.Value.UtcDateTime, expires.Value.UtcDateTime, signingKey);
the second parameter is responsible for the aud claim in the JWT:
From https://msdn.microsoft.com/en-us/library/dn451037(v=vs.114).aspx :
audience
Type: System.String
If this value is not null, a { aud, 'audience' } claim will be added.
After setting the aud claim in the token authorization should work fine.
From what I understood, you need to add the header: Authorization: Bearer "token".
If you have not modified the default implementation of the authorization request the steps are these:
Register user at the endpoint:
/api/Account/Register
Post to /token the following items:
grant_type: password
username: "the username you registered"
password: "the password you registered for the user"
You will receive a token in the Response
Copy that token and create a Request to the method you secured with the [Authorize] filter of type:
Authorization: Bearer "the_token_you_copied_earlier"
Needless to say, it could be pretty easy for you if you used Postman or Fiddler to make and receive Requests because it shows you how everything works.

IdentityServer4 with Resource API in .NET 4.5 (OWIN)

I've read through numerous samples, as well as the IdentityServer 4 documentation, but I still seem to be missing something.
Basically, I have IdentityServer4 working to the point that it is proving me an AccessToken and a RefreshToken. I then try to use that AccessToken and sent an HTTP request to my WebAPI2 (.NET 4.5, OWIN), which uses IdentityServer3.AccessTokenValidation which should be compatible based on samples/tests at https://github.com/IdentityServer/CrossVersionIntegrationTests/
The WebAPI2 is giving me at HTTP 400 when I try to access a resource which required Authorization, and I am truly clueless as to why it happens.
Here is the code:
QuickstartIdentityServer Startup.cs
public void ConfigureServices(IServiceCollection services)
{
var connectionString = #"server=(localdb)\mssqllocaldb;database=IdentityServer4.Quickstart.EntityFramework;trusted_connection=yes";
var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
// configure identity server with in-memory stores, keys, clients and scopes
var identityServerConfig = services.AddIdentityServer()
.AddConfigurationStore(builder =>
builder.UseSqlServer(connectionString, options =>
options.MigrationsAssembly(migrationsAssembly)))
.AddOperationalStore(builder =>
builder.UseSqlServer(connectionString, options =>
options.MigrationsAssembly(migrationsAssembly)))
.AddSigningCredential(new X509Certificate2(Path.Combine(_environment.ContentRootPath, "certs", "IdentityServer4Auth.pfx"), "test"));
identityServerConfig.Services.AddTransient<IResourceOwnerPasswordValidator, ActiveDirectoryPasswordValidator>();
identityServerConfig.Services.AddTransient<IProfileService, CustomProfileService>();
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
InitializeDatabase(app);
app.UseDeveloperExceptionPage();
app.UseIdentityServer();
app.UseMvcWithDefaultRoute();
}
QuickstartIdentityServer Config.cs (that I used to seed my database)
public class Config
{
// scopes define the API resources in your system
public static IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>
{
new ApiResource("api1", "My API")
{
Scopes = new [] { new Scope("api1"), new Scope("offline_access") },
UserClaims = { ClaimTypes.Role, "user" }
}
};
}
// client want to access resources (aka scopes)
public static IEnumerable<Client> GetClients()
{
// client credentials client
return new List<Client>
{
new Client
{
ClientId = "client",
AllowedGrantTypes = GrantTypes.ClientCredentials,
ClientSecrets =
{
new Secret("secret".Sha256())
},
AllowedScopes = { "api1" }
},
// resource owner password grant client
new Client
{
ClientId = "ro.client",
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
ClientSecrets =
{
new Secret("secret".Sha256())
},
UpdateAccessTokenClaimsOnRefresh = true,
AllowedScopes = { "api1", "offline_access" },
AbsoluteRefreshTokenLifetime = 86400,
AllowOfflineAccess = true,
RefreshTokenUsage = TokenUsage.ReUse
}
};
}
}
WebAPI2 Startup.cs
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
{
Authority = "http://localhost:44340/",
RequiredScopes = new[] { "api1" },
DelayLoadMetadata = true
});
WebApiConfig.Register(config);
app.UseWebApi(config);
}
WebAPI2 TestController
public class TestController : ApiController
{
// GET: api/Test
[Authorize]
public async Task<IHttpActionResult> Get()
{
return Json(new { Value1 = "value1", Value2 = "value2" });
}
}
ConsoleApplication to test this:
private static async Task MainAsync()
{
// discover endpoints from metadata
//DiscoveryClient client = new DiscoveryClient("https://dev-ea-authapi");
DiscoveryClient client = new DiscoveryClient("http://localhost:44340/");
client.Policy.RequireHttps = false;
var disco = await client.GetAsync();
// request token
var tokenClient = new TokenClient(disco.TokenEndpoint, "ro.client", "secret");
var tokenResponse = await tokenClient.RequestResourceOwnerPasswordAsync("likosto", "CrM75fnza%");
if (tokenResponse.IsError)
{
Console.WriteLine(tokenResponse.Error);
return;
}
Console.WriteLine(tokenResponse.Json);
Console.WriteLine("\n\n");
//var newTokenResponse = await tokenClient.RequestRefreshTokenAsync(tokenResponse.RefreshToken);
// call api
var httpClient = new HttpClient();
httpClient.SetBearerToken(tokenResponse.AccessToken);
var response = await httpClient.GetAsync("http://localhost:21715/api/test");
if (!response.IsSuccessStatusCode)
{
Console.WriteLine(response.StatusCode);
// HTTP StatusCode = 400 HERE <======================
}
else
{
var content = response.Content.ReadAsStringAsync().Result;
Console.WriteLine(JArray.Parse(content));
}
}
After looking at this more closely, it was because I was adding some very large data sets to my token as experimentation. IIS was sending the HTTP 400 because the request headers were too long.

ASP.NET Identity is null even the token is sent

For my thesis Project i have to implement a token-based (Bearer) Authentication in my ASP.NET solution. I implemented it like Taiseer Jouseh (http://bitoftech.net/2014/06/01/token-based-authentication-asp-net-web-api-2-owin-asp-net-identity).
The basic part is working correctly. I have a Mobile Client on which i can register a new User. Then i can Login and receive the token. When i then make a request, the token is sent in the Request Header. It all works fine.
My problem is, that I get an 401 Unauthorized error if I call a [Authorize] Method, even if i send the token. So i removed the [Authorize] Annotation to test some things:
var z = User.Identity;
var t = Thread.CurrentPrincipal.Identity;
var y = HttpContext.Current.User.Identity;
var x = Request.GetOwinContext().Authentication.User.Identity;
Here i got alwas the same Identity: AuthenticationType=null; IsAuthenticated=false; Name=null; Claims:empty
var token = Request.Headers.Authorization;
Here i get the right token. So the token is sent by the request.
I hope you can help me. I have the token but no identity.
Here are parts of my code:
OAuthServiceProvider:
public class SimpleAuthorizationServerProvider : OAuthAuthorizationServerProvider
{
public async override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
}
// POST /token
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
var userManager = DependencyResolver.Current.GetService<UserManager<IdentityUser, int>>();
IdentityUser 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 = await userManager.CreateIdentityAsync(user, context.Options.AuthenticationType);
identity.AddClaim(new Claim("sub", context.UserName));
identity.AddClaim(new Claim("role", "user"));
context.Validated(identity);
}
}
The Controller Method:
#region GET /user/:id
[HttpGet]
[Route("{id:int:min(1)}")]
[ResponseType(typeof(UserEditDto))]
public async Task<IHttpActionResult> GetUser(int id)
{
try
{
// tests
var z = User.Identity;
var t = Thread.CurrentPrincipal.Identity;
var y = HttpContext.Current.User.Identity;
var x = Request.GetOwinContext().Authentication.User.Identity;
var token = Request.Headers.Authorization;
User user = await _userManager.FindByIdAsync(id);
if (user == null)
{
return NotFound();
}
Mapper.CreateMap<User, UserEditDto>();
return Ok(Mapper.Map<UserEditDto>(user));
}
catch (Exception exception)
{
throw;
}
}
#endregion
The WebApiConfig:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter("Bearer"));
config.MapHttpAttributeRoutes();
var corsAttr = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(corsAttr);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
Startup:
[assembly: OwinStartup(typeof(Startup))]
public class Startup
{
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
var container = new UnityContainer();
UnityConfig.RegisterComponents(container);
config.DependencyResolver = new UnityDependencyResolver(container);
//config.DependencyResolver = new UnityHierarchicalDependencyResolver(container);
WebApiConfig.Register(config);
app.UseWebApi(config);
ConfigureOAuth(app);
}
public void ConfigureOAuth(IAppBuilder app)
{
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new SimpleAuthorizationServerProvider()
};
// Token Generation
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
app.UseOAuthAuthorizationServer(OAuthServerOptions);
}
}
Finally I found the problem. It is so simple, that I can't believe I spent more than a week to solve this problem.
The problem was in the startup. I simply had to call ConfigureOAuth(app); before app.UseWebApi(config);
So the correct Startup looks like
[assembly: OwinStartup(typeof(Startup))]
public class Startup
{
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
var container = new UnityContainer();
UnityConfig.RegisterComponents(container);
config.DependencyResolver = new UnityDependencyResolver(container);
//config.DependencyResolver = new UnityHierarchicalDependencyResolver(container);
WebApiConfig.Register(config);
ConfigureOAuth(app);
app.UseWebApi(config);
}
public void ConfigureOAuth(IAppBuilder app)
{
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new SimpleAuthorizationServerProvider()
};
// Token Generation
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
app.UseOAuthAuthorizationServer(OAuthServerOptions);
}
}
My guess is that the token is not being sent correctly from the client. Are you sending the Authorization token with word "Bearer" prefixed in front ?
the Authorization Header should be something like below -
Authorization:Bearer reNjoIUZBJHCMigQJHzCgMMVUyu4vg
Look in the chrome developer tools network tab to see what is being sent.

How to get or create a Token

I am trying a token tutorial with web-api and I'm a little confuse, I can't figure how to get my Token, according to the tutorial the token comes from endpoint of Web Api, but I dont understand what is the specific function that produce the token or how to call it so I will get a token back to GetToken(), here some code:
class Startup
public void ConfigureAuth(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions()); app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
string PublicClientId = "self";
OAuthAuthorizationServerOptions OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new PureApi.Provider.ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Login"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
app.UseOAuthBearerTokens(OAuthOptions);
}
my LoginController
static string GetToken(string userName, string password)
{ var pairs = new List<KeyValuePair<string, string>>
{new KeyValuePair<string, string>( "grant_type", "password" ),
new KeyValuePair<string, string>( "username",userName ),
new KeyValuePair<string, string> ( "Password", password ) };
var content = new FormUrlEncodedContent(pairs);
using (var client = new HttpClient())
{
var response = client.PostAsync("http://localhost:2188/api/Test",content).Result;
return response.Content.ReadAsStringAsync().Result;
}
}
class Provider
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);
}

Categories