The ASP.NET team has shipped new samples showing how to use the identity packages. They are contained in the following nuget package: Microsoft Asp.Net Identity Samples
The samples are very helpful, but there have been loads of changes from how things were done originally in the templates that shipped.
My specific question: In the original SPA template, there was the following code:
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId, UserManagerFactory),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
...
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
But in the new samples in the nuget package, that code is gone, and in its place is this code:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(validateInterval: TimeSpan.FromMinutes(30), regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});
Can anyone help me understand the difference between app.UseOAuthBearerTokens and app.UseCookieAuthentication (and why this change was made)? They both seem to allow the application to behave in the same way and I could use some clarification on this change.
Thanks...
-Ben
OAuth is used for API security, IN API you would not use cookies and this is essentially stateless. However on say a normal MVC or forms website, you would use a normal session cookie. unless you are creating an API I would not worry about OAuth, and just go with the traditional cookie based auth.
If you want to create an API, then you need to, and I would say MUST DO OAuth for your validation. You would then send a token with your request, post, put, delete. This token is decoded backend by the handlers to reveal permissions, User ID etc
Thought it would be best to extend this and explain the problems, and why OAuth solves it.
Usually an api would be on a separate domain to the UI, be that an APP, Website etc. If you did manage to be given a cookie from an API ( for example facebook.com ) You would only be able to use this cookie on facebook. But your website would be www.myblog.com. There are settings in Ajax to enable the passing of cookies with ajax request, however the domain must be the same, and this is still rather sketchy.
So Oauth Is born, essentially creating what could be best described as a string based cookie, that can be stored however you like, so long as it is passed back, with your requests, within the request headers.
You can in browser applications use javascript to create a cookie, and save your token within this cookie. This would allow you to take advantage of the persistent storage. However it is probably better to use available local storage. So for a browser based app, this would be LocalStorage API, for desktop apps you could use temp storage, local db, etc. and phone apps will have something similar.
Related
I have an old ASP.Net MVC 5 application that already implements Identity framework to log users into the website. We have started moving to a micro services architecture and now have the need to authenticate requests made to the api's (api's are in .net core).
I have successfully managed to create an identity server and using postman with the ResourceOwnerPasswordAndClientCredentials flow able to create a jwt token, and authenticate a user on the API whilst also drawing out claims.
The mvc application has a login page similar to airbnb (the login form is a popup on the home page) so redirecting off the website to identity server is not really an option.
Question is what flow am I suppose to be using?
My client in identity server currently looks like this:
new Client
{
ClientId = "ClientWebsite",
ClientSecrets = new[] { new Secret("secret".Sha256()) },
AllowedGrantTypes = GrantTypes.ResourceOwnerPasswordAndClientCredentials,
AllowedScopes = new[] {
"WebsiteAPI",
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email
}
},
As mentioned in client website is already setup to authenticate using Cookie Authentication, startup looks like this:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString(Settings.FormsAuthPath),
Provider = new CookieAuthenticationProvider
{
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});
I know that i need to add something after this. Any help would be appreciated.
Since you're aiming for full control of the login page, I would definitely say you're on the right path with the ResourceOwnerPassword flow. I'm not sure why you wanted to include the client credentials grant type as well, but it's not needed for user authentication the way you specified.
From what you have built so far, I recommend making sure everything that is needed for the resource owner password flow is implemented. the main thing that needs to be done for this flow is the implementation of the IResourceOwnerPasswordValidator interface specified here. After that, you should be able to make direct requests to the token endpoint 'connect/token'. As long as you have all the proper fields specified in your form post (grant_type, username, password, and scopes as described by in the spec), you should get your access and id token with no problem!
Needing help from anyone.
I have a SPA client application that is talking to a WebApi (.Net 4.52). Both have been developed by my company. It has been working quite fine with tokens that the WebAPI has been generating itself (based on the excellent articles from bitoftech)
We now want to allow authentication with Azure - more specifically, my customer's own azure tenant (which I have no direct control over). To do this on the client-side, we use adal.js to do the back and forth with actually signing the user in, and we use UseWindowsAzureActiveDirectoryBearerAuthentication on the server-side to validate the azure tokens.
The Oauth startup looks like this:
public static void RunAcademyOAuthStartup(IAppBuilder app)
{
if (ConfigurationManager.AppSettings["ida:Enabled"] == "1")
{
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters
{
ValidAudience = ConfigurationManager.AppSettings["ida:Audience"],
AuthenticationType = "ExternalAzureSSO"
},
Tenant = ConfigurationManager.AppSettings["ida:Tenant"]
}
);
}
var apiAccessTokenLifeTimeSeconds = 0;
if (!int.TryParse(ConfigurationManager.AppSettings["ApiAccessTokenLifetimeSeconds"], out apiAccessTokenLifeTimeSeconds))
{
apiAccessTokenLifeTimeSeconds = 1800; //set default to 30 minutes
}
var oAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/api/user/authenticate"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(apiAccessTokenLifeTimeSeconds),
Provider = new SimpleAuthorizationServerProvider(),
RefreshTokenProvider = new SimpleRefreshTokenProvider(),
AuthenticationType = "LocalApplication"
};
OAuthBearerOptions = new OAuthBearerAuthenticationOptions();
// Token Generation - setup the token authorization server
app.UseOAuthAuthorizationServer(oAuthServerOptions);
app.UseOAuthBearerAuthentication(OAuthBearerOptions);
}
The code above is no different to hundreds of other examples I've been trawling through for days.
This all works fine when I use my free Azure instance (through my company's MSDN) - I can authenticate, the token comes back from azure, webapi can decode it and validate and it continues on.
My problem arises when I try this against my customer's P1 Azure instance - I can authenticate, get a token back, but my webapi does not decode the token. There is no errors logged as far as I can see.
The main thing I can see at the moment is when I get the azure token and decode it using jwt.io, I can see the "x5t" and "kid" values. Based on other information I have found around the 'net, I should be able to get the latest keys from https://login.microsoftonline.com/common/discovery/keys and find either the "x5t" and/or the "kid" values in there....but I can't.
Is this possible? What would cause a token to be generated with keys other than the common ones? Is this a configuration item within the app registration in azure? Do I need to add more settings to the UseWindowsAzureActiveDirectoryBearerAuthentication config in web api?
Tokens are all v1
An answer for anyone who is coming across this thread in the future...probably a rookie mistake :)
What I found in my case was that the admin on the Azure side had registered my application using the "Enterprise Applications" option in their Azure Portal BEFORE editing the manifest,etc in the "App Registrations" area. According to Microsoft Support, it should be done the other way around - register in App Registrations first, then go to Enterprise Applications (if needed). Doing things in that order means that the azure tenant then generates the tokens and signs them with the "common" keys, and not the custom key that a Enterprise App gets.
I currently have a website where I am trying to implement the OAuth server framework. The website is currently a combination of Web Forms (not MVC) and Web API 2. For the purposes of what I am trying to do, we cannot change the overall architecture of the system.
So far, I have OAuth working via the Web API for validating clients, generating access tokens, and handling refresh tokens.
The last piece I am trying to implement is the Authorize Code workflow. This will allow us to grant access to our application so integration tools can access our APIs without having to locally store the user credentials.
My understanding of how it should function is the following:
User is directed to the AuthorizeEndpointPath that I define in the Startup.Auth file
User either sees a login page (if they don't already have an authentication cookie for the website), or they see a special page where they have to grant permission to access the account (similar to what Google has)
Once the user clicks the "grant" button, the OWIN middleware will process the request, and redirect them back to the original client URL that requested access
However, after all of my configuration, whenever I access the AuthorizeEndpointPath directly, the "grant access permission" page is never actually displayed.
I've ensured the following configuration, but there isn't much documentation on what the correct configuration is.
var oAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/api/token"),
AuthorizeEndpointPath = new PathString("/LoginAuthorize.aspx"),
//AuthorizeEndpointPath = new PathString("/api/authorize"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(10),
Provider = new ApiAuthorizationServerProvider(),
RefreshTokenProvider = new ApiRefreshTokenProvider(),
AuthorizationCodeProvider = new ApiAuthoirzationCodeProvider()
};
Currently the "AuthorizeEndpointPath" property maps to an actual page, where I ask the user confirmation, but that page is not being displayed at all
Through debugging, I can see the framework hits the following method even before the authorization page would be loaded
ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context)
I have tried to overload that method, and one of 2 things happens. If I make a call to context.Validated();, the user is immediately redirected without the authorization page being displayed. If don't "validate" the redirect URI, then a blank page is displayed indicating an "invalid_request".
So the big question is how do I actually make OWIN display my custom authorization page?
When the authorization page is finally displayed, what would I need to do when the user clicks on the "grant" button. Is there any configuration I need to setup, or any calls to OWIN I need to make?
Also, how do I ensure the user authenticates before that page is displayed? Do I simply have my code redirect the user to the login page if they are not logged in? If so, how will OWIN handle the real redirect back to the client (if the user would be redirected to the authorization page once they login)?
Finally, once this is all configured properly, will I still be able to support the current OAuth workflow I have of allowing clients to manually pass in their credentials for the "token" API? The reason I ask is because we also have mobile apps that have their own sign-in screen, and will be using OAuth to connect (in addition to other web-based clients).
I had a question that turned out to be similar to yours.
So, after quite some searching online, I got some success by searching github. Apparently, OAuthAuthorizationServerProvider offers AuthorizeEndpoint and that method should be used for both "Hey, you're not authorized, go log in you!" as well as for "Ahh, okay you're cool, here's an authorization code.". I had expected that OAuthAuthorizationServerProvider would have two separate methods for that, but it doesn't. That explains why on github, I find some projects that implement AuthorizeEndpoint in a rather peculiar way. I've adopted this. Here's an example:
public override async Task AuthorizeEndpoint(OAuthAuthorizeEndpointContext context)
{
if (context.Request.User != null && context.Request.User.Identity.IsAuthenticated)
{
var redirectUri = context.Request.Query["redirect_uri"];
var clientId = context.Request.Query["client_id"];
var authorizeCodeContext = new AuthenticationTokenCreateContext(
context.OwinContext,
context.Options.AuthorizationCodeFormat,
new AuthenticationTicket(
(ClaimsIdentity)context.Request.User.Identity,
new AuthenticationProperties(new Dictionary<string, string>
{
{"client_id", clientId},
{"redirect_uri", redirectUri}
})
{
IssuedUtc = DateTimeOffset.UtcNow,
ExpiresUtc = DateTimeOffset.UtcNow.Add(context.Options.AuthorizationCodeExpireTimeSpan)
}));
await context.Options.AuthorizationCodeProvider.CreateAsync(authorizeCodeContext);
context.Response.Redirect(redirectUri + "?code=" + Uri.EscapeDataString(authorizeCodeContext.Token));
}
else
{
context.Response.Redirect("/account/login?returnUrl=" + Uri.EscapeDataString(context.Request.Uri.ToString()));
}
context.RequestCompleted();
}
Source: https://github.com/wj60387/WebApiOAUthBase/blob/master/OwinWebApiBase/WebApiOwinBase/Providers/OAuthServerProvider.cs
You create a separate login page at /account/login. What this does is sign the user in. If your WebAPI uses cookie-based authentication, you can just redirect the user back to the AuthorizeEndpoint again. If you use access tokens, your login page has to make a request to `AuthorizeEndpoint' with the access token to obtain an authorization code. (Don't give the access token to the third party. Your login page requests the authorization code and sends that back.) In other words, if you use access tokens then there are two clients involved in this flow.
I would like to realize an authentification server with ASP.NET Identity for an mobile app.
But I don't want to use default authentification methods.
I would like to implement an WebApi method which creates session for user by login and password and returns the session id. So, in the mobile app I will add as an json parameter this session id for each request to the server.
Please give me an example how can I implement it?
I have read this article http://bitoftech.net/2014/06/01/token-based-authentication-asp-net-web-api-2-owin-asp-net-identity/, but I also need an WebApi method to destroy the session, that is not possible as it described there.
First of all:
How would you make sure the session is "destroyed"?
You can't be sure. The user could lose connection to the internet or hard shutdown his device.
Now, to answer your question.. kind of:
What you need is a token that expires. This would make sure that the user is logged out after some time. You could do this by making a relatively short expiration time and then make sure this time i reset whenever the user uses the key to access the web service.
Taiseer's tutorial on Bit of Tech is excellent, for understanding the basics of Identity Framework and Token Based authentication.
Taiseer sets the Expiration time on his access tokens when he configures the OAuth in Startup.cs:
public void ConfigureOAuth(IAppBuilder app)
{
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1), //<---- Right here
Provider = new SimpleAuthorizationServerProvider()
};
// Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
You could do something like:
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30)
Then you would have to find a way to refresh the token lifetime each time it is used. I don't have a suggestion for you at the moment, but maybe someone else does. You could do this by overriding the AuthorizeAttribute.
Taiseer also has a great guide on RefreshTokens which might come in handy:
http://bitoftech.net/2014/07/16/enable-oauth-refresh-tokens-angularjs-app-using-asp-net-web-api-2-owin/
I'm trying to create a simple proof of concept OAuth enabled application but am stuck on the authorization code implementation. Everywhere I read seems like it goes in one way or another, never actually using the authorization code flow. I've been using the following resources for information:
https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-31
https://aaronparecki.com/articles/2012/07/29/1/oauth2-simplified
http://www.asp.net/aspnet/overview/owin-and-katana/owin-oauth-20-authorization-server
I have setup web api and owin with a custom OAuthAuthorizationServerProvider to accept password grant types for refresh tokens and the ability to exchange a refresh token for an access token. This is working well, but I want to setup a scenario where I redirect a browser to the server to authorize and redirect back to the client with an authorization code. I then want the client to sent the authorization code to the token endpoint to get a refresh token
In the second link under Web Server Apps, I'm trying to get my web api app to surface an authorization code from a request like, http://127.0.0.1/auth?response_type=code&client_id=123&redirect_uri=http://validredirect.com&scope=access, but I keep getting a 404.
I've configured owin as follows:
var databaseContext = new AdnsfContext();
WebApp.Start(
new StartOptions("http://127.0.0.1:7000"),
appBuilder =>
{
var httpConfig = new HttpConfiguration();
httpConfig.MapHttpAttributeRoutes();
httpConfig.SuppressDefaultHostAuthentication();
httpConfig.Filters.Add(new HostAuthenticationFilter("Bearer"));
appBuilder
.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true,
ApplicationCanDisplayErrors = true,
AuthorizeEndpointPath = new PathString("/auth"),
TokenEndpointPath = new PathString("/token"),
AuthorizationCodeExpireTimeSpan = TimeSpan.FromMinutes(1),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(1),
Provider = new AuthServerProvider(),
AuthorizationCodeProvider = new AuthorizationCodeProvider(),
RefreshTokenProvider = new RefreshTokenProvider(),
})
.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
{
AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Active,
AuthenticationType = "Bearer",
})
.UseCors(CorsOptions.AllowAll)
.UseWebApi(httpConfig);
});
The pieces I've added to enable the authorization endpoint are the properties for the auth server options:
AuthorizeEndpointPath = new PathString("/auth"),
AuthorizationCodeExpireTimeSpan = TimeSpan.FromMinutes(1),
AuthorizationCodeProvider = new AuthorizationCodeProvider(),
The overrides in my implementation of the AuthorizationCodeProvider throw not implemented exceptions but it's currently not even hitting any breakpoints set in the code. One thing to note is that when I use postman to hit the auth endpoint, I get a server header back for HTTPAPI/2.0 which is different than if there simply isn't something surfaced at that endpoint, which means I must be sending the request incorrectly. Can anyone see a problem with my setup? Thanks in advance, I know that this is clearly my failing in understanding OWIN and OAuth.
One thing to note with the OAuth2 authorization server built in Katana is that it's transparent: you must provide your own /auth endpoint (using MVC or Nancy for instance) or directly render your consent form in OAuthAuthorizationServerProvider.AuthorizationEndpoint
You can take a look at https://github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Server/tree/dev/samples/Mvc for a complete sample. It doesn't use the OAuth2 authorization server built in Katana but a much more elaborated fork targeting OpenID Connect but you should get the idea.
Take a look at IdentityServer. It's based on Owin.
There is also samples repository where you can find a lot of examples using selfdeployed and\or 3rd party identity providers.
I think that this one example is most appropriate for you.