I am experimenting in developing Single Page Application using Asp Mvc 4 / Web Api and angularjs.
I am using the mvc controller actions to return views and web api actions to return json.
As the web api part is restfull and it has no state, I am wondering how to check if a user session has expired. For example: a user is clicking on a button and this leads to request to the web api action to get some json data. But when the request hits the server I want to check if the user session has expired.
As I said I am rather new to this combination of technologies and I am wondering how can this be achieved. Any example will be greatly appreciated. Thanks in advance.
Web API introduced an Attribute [Authorize] to provide security. This can be set globally (global.asx)
public static void Register(HttpConfiguration config)
{
config.Filters.Add(new AuthorizeAttribute());
}
Or per controller:
[Authorize]
public class ValuesController : ApiController{
...
If your user is authenticated(session has not expired) the service will work normally if not an http 401 unauthorized is returned.
This is how I did it in my project: First instantiate a session on client sidei.e in your MVC Application if the user logs in , once the session is created,with each request you should add a unique identifyable token or session id in the header of your WebApi request which you are going to send, If the user sends a request without logging in there would be no token present in the header of the request.
If in your service you get an authentication token which you can verify, that means the request is authenticated and hence session was still in place otherwise the user sent the request without a session in place and hence no token present in the header of the request.
You could add headers with your request like this :
HttpClient httpClient = new HttpClient();
// Add a new Request Message
HttpRequestMessage requestMessage = new HttpRequestMessage(...);
// Add your custom headers
requestMessage.Headers.Add("authToken", "SessionId");
or
requestMessage.Headers.Add("authToken", "encryptedUsername:encryptedPassword");
And then in your WebApi Service read those headers, if you can uniquely identify or verify the authToken then that means the session was in place else unauthenticated request , generate an error response.
I dont know if this is the best practise or not but I did it this way. I actually store the encrypted username & password in my session and attach it with every request and in my WebApi I extract these header values and recheck them with my database and then further process the request. I know many people would not be too much happy about storing passwords in the session but I think its not that bad, they are in encrypted form atleast. Rest is upto you , you could store a sessionId instead or a unique identifier or a flag that may indicate that the session was actually in place and request is authenticated.
Related
I've been using Identity Server 4.0 as my OpenId Connect provider. I can setup clients in Identity Server with Redirect Uris and Post Logout Redirect Uris. I've also been using the angular-auth-oidc-client to login/logout via the Identity server.
When logging in, my client library (angular-auth-oidc-client) does pass in the correct Uri specified in the config when calling the authorize endpoint. When I try to login with an incorrect Redirect Uri, Identity Server checks and validates that the Uri provided by the client is one of the accepted one for that client, and shows an error if it isnt (as expected).
When it comes to logout, none of it seems to be built in. My client library does not send the PostLogoutRedirectUri when calling the logout endpoint. Identity Server's sample code for logout does not except any URIs to be passed in. It's sample code simply gets the Post Logout Redirect Uri value from the database and creates a link on the logged out page. Not only does the sample code not allow the user to specify the Redirect Uri for logout, but it doesn't do any checks or even do a redirect (granted its only sample code and I can change it). I would expect my client library to pass the Uri along and Identity Server to redirect to the Uri after successful logout as long as its one of the "approved" Uris for the client.
My question is: What even is the point of PostLogoutRedirectUri? Neither Identity Server nor the OIDC client library I'm using do anything useful with it. There doesn't even seem to be an agreed upon convention for the name of the query string parameters to use to pass this Uri to Identity Server. And yet, both the Identity Server and the angular client library seem to have some support for it. So what's the point of this thing? Is it something that will be added or fleshed out later? Did I miss some documentation describing what its for and how to use it?
It's a draft standard and support differs between libraries and vendors, but here is a summary:
A client uses the post logout redirect URI to log out in a controlled way, typically redirecting to an application page that gives the user a link to sign in again
A client could potentially have more than one post_logout_redirect_uri and decide which to use based on runtime conditions
The post_logout_redirect_uri sent is meant to only be honoured if it is accompanied by an id_token_hint - and if it matches a configured value against the OAuth client. I believe OIDC will send the current id token but it is worth checking that this is happening in your browser tools.
If a post_logout_redirect_uri is not sent then the Authorization Server may use the default one configured
See the official IETF docs on how this is meant to work.
In my own application, I set it to the /Signout-callback-oidc URL of the client, like
PostLogoutRedirectUris = { "https://localhost:5001/signout-callback-oidc" },
The /signout-callback-oidc path is defined as in the source code here:
/// <summary>
/// The request path within the application's base path where the user agent will be returned after sign out from the identity provider.
/// See post_logout_redirect_uri from http://openid.net/specs/openid-connect-session-1_0.html#RedirectionAfterLogout.
/// </summary>
public PathString SignedOutCallbackPath { get; set; }
I hope this can give some clarification.
There are two sessions, one in the UI, and another on the server. It might need to call a URL on the backend to remove the user session on the server, otherwise the server won't know you are logged out on the UI.
I have a web api and MVC project,
The web api is deployed at api.domain.com
The MVC app is deployed at domain.com
I recently secured certain methods on the API, it requires authentication (grant type: password).
I want to have the token passed around in the code behind of the MVC app and not javascript, to keep it secure and away from someone sniffing angular js traffic.
I did some research and I should use the HttpClient class. If this is the case how does this client handle refresh tokens? Right now the token expires after 8 hours, I know a refresh token is also issued but does the HttpClient automatically handle this or do I have to write my own logic to check if a request was denied due to an expired token.
Thank you!
I did some research and I should use the HttpClient class. If this is
the case how does this client handle refresh tokens?
The HttpClient class is, as its name suggest, an HTTP protocol client. It knows strictly nothing about OAuth 2.0 and in this respect nothing about refresh tokens. So you should write this logic yourself. Basically the flow you should follow is something along those lines:
Send an HTTP request t othe target endpoint using the HttpClient and including your existing OAuth Bearer token in the Authorization header field.
If the request succeeds then you are good to go. If the request fails with 401, then you should use your refresh token in order to renew your access token and then repeat step 1 with your new access token.
I think using a HttpMessageHandler can help you.
The way this is wired up to an HttpClient is by using the HttpClient constructor that takes a HttpMessagHandler:
1: // Create client and insert an OAuth message handler in the message path that
2: // inserts an OAuth authentication header in the request
3: HttpClient client = new HttpClient(new OAuthMessageHandler(new HttpClientHandler()));
The HttpClientHandler is the default “network” handler provided by HttpClient that actually sends the request and received the response from the network.
Refer this for complete detail: https://blogs.msdn.microsoft.com/henrikn/2012/02/16/extending-httpclient-with-oauth-to-access-twitter/
I think I may have phrased the question wrong. What I have currently is an MVC Web Application that (by default) uses bearer tokens. This is all well and good but if I want to communicate with any of these APIs outside of the Web Application, I would like to use a REST client. However, I can not find a way to generate a bearer token/call the Login method and get a bearer token back to be used as an authorization header in subsequent requests.
What I hope to have:
POST /Account/Login
Returns: token
POST /Product/Create
Token Header
Body Request
Returns: success or failure
ETC. All without losing the existing functionality of the website.
Thanks for any help!
The /Token endpoint already provides all the functionality you need in order to use [Authorize] on your WebAPI methods. The general process to make this work would be something like the following:
Client establishes a POST request to http://somesite.com/Token. The Content-Type header should contain x-www-form-urlencoded. The payload body should include grant_type=password&username="username"&password="password". The grant_type value indicates that we are presenting a password in exchange for an access token.
The server response will either be a HTTP 403 or an HTTP 200. In the case of HTTP 200, the response body will include access_token, token_type (bearer), and expires_in.
The client optionally stores this access_token for future access, then establishes a new request to the protected server resource, including a header Authorization, which will be Bearer access_token. This format is important, it must start with Bearer and a space, then the access_token value.
Note that this does not take into account issues of Cross Origin Requests (CORS), or HTTPS. Proper security should be enacted whenever a username or password is sent, as in step 1 here.
This is configured by default on any new MVC5 project with Identity. You will find a Startup class similar to the following:
public partial class Startup
{
// Enable the application to use OAuthAuthorization. You can then secure your Web APIs
static Startup()
{
PublicClientId = "web";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
AuthorizeEndpointPath = new PathString("/Account/Authorize"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
}
The TokenEndpointPath represents your path for token requests, the AuthorizeEndpointPath represents the path used when External Logins (Facebook, Twitter, Google, etc.) are used. See this Microsoft article for more info on the default template.
A much more detailed step by step of this process and complete client application written in Angular.js can be found on a blog by Taiseer Joudeh.
I'm working with OAuth 2.0 for MVC, found here: http://community.codesmithtools.com/CodeSmith_Community/b/tdupont/archive/2011/03/18/oauth-2-0-for-mvc-two-legged-implementation.aspx
For anyone who's worked with this - I'm confused about the RequestToken. There is a controller implemented that lets you get a request token, which expires in 5 minutes, and you pass that token back in to get an AccessToken. But it never checks the request token for validity - it seems like you can pass in any access token you want to. What is the idea for the RequestToken here - are you supposed to create your own method of storing, referencing, and then deleting that token for those 5 minutes?
Thanks,
Andy
This is all about how OAuth works in conjunction with your application Id, application secret key and valid domains for your application. Here is the process in general
Your application sends a request to the OAuth provider using your application Id and secret along with a callback (return Url).
The OAuth provider gets the request, checks your application Id and secret and validates that the callback url is from a domain that you have specified for your application.
2a. If the callback url is not from a domain that you have specified, then the request is rejected with error.
2b If the callback url is from your domain, it returns a temporary request key to your server.
Given that you received a request key, you send that back to the OAuth provider to get the actual access token for the user.
Now, as to why the request key step is in place, this is to prevent and help protect 'bad people' from attempting to use your application id to falsely authenticate other users. By sending the request token to you (a callback URL that you have approved), the OAuth provider has confidence that the request actually came from your servers.
You most certainly could send any string back instead of the request token, but you would quickly get an error back from the OAuth provider as that request token does not correspond to any existing authentication request from any known application.
Lastly, I am not clear on what you mean by 'validating the request token'? You did not generate the token not probably do not have insight into the algorithm to generate the request token. Given that, I am not sure how you would validate this. If you are concerned about validating the first step, take a look at the Facebook OAuth process. In there, they recommend sending a request key as part of your return Url(as a query string parameter). That request key will come back to your application which you could then use as a validation that, indeed, this is a response to a request that you made. How you store and track that request key is up to you (session, database). In the PHP samples, they use a 'state' variable to track a unique/arbitrary string: Facebook OAuth Server Side Login Example (in PHP)
I'm using DotNetOpenAuth to connect to Facebook and Google via OAuth2. The OAuth specs ask that no additional parameters be supplied in the request_uri and Google actually enforces this somewhat by forcing to to specify an exact call back uri when you define your Google App with them.
What I want to accomplish is to be able to return the user to a specific URL after they have been authenticated with Facebook or Google. The flow is this, the user clicks on a protected link, they get forwarded to my login page with a returnUrl parameter and then I kick off the authorization process based on the OAuth2 authorization server they choose.
Since the request_uri can't have any parameters in it (though Facebook lets you get away with this), I can't send the returnUrl parameter to the authorization server and get it back such that when the user is returned to my site, I forward them to the protected page they were trying to access. The best I can do is to forward them to the homepage or a member welcome page.
The way to fix this is to use the "state" parameter which the authorization server will send back to the request_uri, but I can't find a way to specify this with DotNetOpenAuth.
By default, it looks like the code uses the SessionID as the state parameter to verify the request coming back from the authorization server. Specifying an IClientAuthorizationTracker on the WebServerClient class lets me plug in my logic when the response is coming back from the authorization server but it's not called when the authorization request is being prepared, so I can't plug in my additional state.
This is code from WebServerClient.cs's PrepareRequestUserAuthorization:
// Mitigate XSRF attacks by including a state value that would be unpredictable between users, but
// verifiable for the same user/session.
// If the host is implementing the authorization tracker though, they're handling this protection themselves.
if (this.AuthorizationTracker == null) {
var context = this.Channel.GetHttpContext();
if (context.Session != null) {
request.ClientState = context.Session.SessionID;
} else {
Logger.OAuth.WarnFormat("No request context discovered, so no client state parameter could be set to mitigate XSRF attacks.");
}
}
There is no else block here which is what I would have expected to be able to play along and plug in my own data.
Any tips on what I'm missing?
The state parameter is necessarily preoccupied with mitigating XSRF attacks. Since you already have a user session, can you just store the returnUrl in the session dictionary?
Alternatively, you can file an issue with DotNetOpenAuth asking that you be allowed to bundle your own data into the state parameter (along with DNOA's own XSRF mitigation code).