Refresh identity token from client from code - c#

I am using the fine-uploader with an asp.net mvc backend to upload files directly to an azure blob-storage. The asp.net-server works as the azure-signature-endpoint(sas). This is all secured with an identityserver3 and here comes the problem: The identity_tokens lifetime is set to 5 minutes(as default). And I want the SAS endpoint to be only called authorized. So a user can only access its own data. But after I have the upload running for the set 5 minutes, it breaks. Of course, because it is not authorized and it returns the login-page from the identity-server(which the fine-uploader, of course, can't handle).
It would be easy to solve this problem, by either setting the lifetime from the token to something higher(but this is unreliable as the upload could take hours or days), or disable the lifetime(yeah would work. But I guess the lifetime has a reason to exist).
So my 2 ideas would be:
to just authorize the user once(when he starts the download)
or to refresh the token by code every time the signature gets generated.
First approach
Can I just set a boolean like user is authorized and if this boolean is set just skip authorization and just return the signature or how could I achieve this
Second approach
How would I do this?

Don't use the id token for API access, an instead use access token. Access tokens are for resources (APIs), whilst id_tokens are purely for authentication. The id_token is only meant to be used to provide the RP with means of knowing who the user is - hence no need for long time span. It's only there for converting into a user session (cookie/principal).
With access tokens you have several approaches for keeping a valid token at a client; either by fetching new ones using the client credentials flow or by using the refresh token approach.
I believe there are samples of both in the samples repo of IdentityServer.
Samples repo link

Related

Ways to secure an anonymous Web API request

I have a ASP.NET MVC (NOT ASP.NET Core) single page application with angular js on the front end.
My client (browser) talks to server through ASP.NET Web APIs. Now, the web application is on https but anonymous. There is no login/ user authentication.
The web app is in the form of a wizard where user can go back and forth and add or update input fields on the web page. The form input values are then updated on the server through Web API.
I'm looking for a way to secure my Web API calls alone, especially the POST/ PUT requests. In summary, I want to prevent any user calling my Web API directly from POSTMAN or Fiddler. The Web API, though anonymous can be only called from the browser session where the request originated.
What are options do I have to achieve this?
Can I use Anti-Forgery token here (without authentication)?
One way, I can think of achieving this is to add a custom header to each request and store some kind of session key in the header. Then, validate the custom header on every request I received from client. Are any other ways of achieving this out-of-box or some proven library without going for custom solution?
If I have to go for the above custom solution, what are the pitfalls or potential issues I need to be aware of?
First of all when you remove login and there's no authentication mechanism in your application, there's really no way to secure anything, because anyone can access your APIs. I think what you want is to make sure that your APIs are called only from your own website. Unfortunately you can't completely achieve that, since your web APIs are http/https, and anyone, from anywhere (like postman, fiddler, ...) can create a http request and call your API.
All you can do is to make it harder for your API to response to requests, like using Anti-Forgery as you mentioned.
And also I suggest you add a cookie for your application and check that cookie in every request, in this case it's more complicated ( not impossible ) to call your API using Fiddler or Postman.
And last I suggest that you use CORS, so browsers would only allow your domain to call your APIs. So nobody can call your APIs in a browser from different domain.
Based on answer from #Arvin and comment from #Evk, here's how I plan to proceed:
Once, the user starts the anonymous session generate a GUID using regular Guid.NewGuid() method and save it in DB to identify the request (I'm doing this now). However, as mentioned here,
GUID can be unique but they are not cryptographically secured.
Hence, instead of using plain-text GUID, encrypt it with current timestamp as token and append it with request query string.
For every subsequent API request, read the token from query string, decrypt it and validate it as follows:
Check the timestamp. If the time difference is more than pre-defined time (i.e. token expired), reject the request
Validate the unique id (GUID) against DB
Since, I'm not using plain text GUID anymore, the URI would not easy to guess.
Additionally, with the timestamp, URI is invalidated after sometime. While theoretically it is still possible to call the API through Fiddler but this should make it very difficult for the attacker, if not impossible.
As a further security measure, I can also add Anti-Forgery token to the request
As per my understanding this helps solving my underlying problem and with this approach, I may not even need add a cookie to secure my anonymous session.
Love to hear from you all if this approach looks good and how can it be improved.
I also once had the weird need for having session functionality on WebAPI and created an OWIN Session middleware that does exactly what you're aiming for.
The library is called OwinSessionMiddleware and is available on github and NuGet.
Usage
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseSessionMiddleware();
// other middleware registrations...
app.UseWebApi();
}
}
You can also pass some options to further tweak cookie-name, add a database backed session store (instead of in-memory), add your own session id generator (instead of default id generator which is based on GUID + secure random part generated by RNGCryptoServiceProvider).
The unique session id itself is stored as a secure cookie and the session is restored automatically by the middleware on each request.
There are extension methods you can call inside your API controller to get and set session data:
public SomeApiController : ApiController
{
public IHttpActionResult MyAction()
{
var requestCount = Request.GetSessionProperty<int>("RequestCount");
Request.SetSessionProperty("RequestCount", ++requestCount);
}
}
Create Anonymous JWT token with some claims related to your scenario, Sign it with some key, Use that as in cookie (Http Only) or As bearer token. To make it little more harder further combine it with some cookies.
1)verify token signature and
2) Verify token expiry time
3) Verify Claim(skey) against cookies(skey)- no database storage required everything is in ur JWT token.

Webapi oauth accestoken invalid expiration date

We are building a frontend application that is making extensive use of an webapi backend.
In this application we are using oauth to log a user in and store all of the claims that belong to that user inside off access tokens.
On the frontend we are using sentry error logging (http://www.getsentry.com) to log all of our javascript errors. This includes any webapi calls that somehow went wrong or do not return the result we are expecting. With every error we recieve we also log the cookie information along with it, which includes the access tokens that that specific user was using at that time.
Right now we are seeing alot of webapi calls that went wrong because the calls they made are forbidden. I checked some of their access tokens and immeadiately i noticed that the information was way out of date and should have been refreshed a long time ago because the access token should have expired already.
By using :
var ticket = Startup.OAuthOptions.AccessTokenFormat.Unprotect("tokenhere");
on my localhost machine inside the debugger i can unprotect the access tokens and view the information inside of them.
Like i said the information inside some of these tokens contains invalid information and should have been refreshed already..
Then i noticed that the reason they are not refreshed yet is because the ExpiresUtc is more than 2 years bigger than the IssuedUtc. In other words; The token wont expire until after 2 years.
Here is some example information of one of these tokens
IssuedUtc: { 20/02/2016 03:04:40 +00:00}
ExpiresUtc: {16/11/2018 03:04:40 +00:00}
We are using the default expire time from oauth (20 minutes) and somehow in the pipeline it is setting it to be bigger than 2 years. The only way a user can now refresh their claims is if he logs out and back in again, and obviously until they do so it is creating alot of errors on the frontend side.
By debugging my own tokens i can verify that it is setting it to 20 minutes and have never managed to reproduce it myself.
Solved, we had an controller method hidden somewhere that was issueing access tokens with an expiry date of 2 years.. Doh

In WCF/WIF how to merge up claims from two different client's custom sts's tokens

I'm trying to create something like: Client authenticates and gets token from custom STS1, next client authorizes with machine key and is issued token on custom STS2 and gets another token. With last token, client requests methods on RP service.
All services are hosted on IIS and are using active federation scenario.
Both STS's have endpoints with ws2007Federation and ws2007Http bindings, and RP use ws2007FederationBinding with STS2 as an issuer.
If I create channel with CreateChannelWithIssuedToken I can see only token from STS1 and can't get token from STS2.
So I decided to pass token from STS1 as ActAs RST's property on request to STS2 token. And that failed - cannot decrypt token.
How can I pass both tokens to STS2 and merge up claims in them?
Is it a bad idea - to send with RST just extracted claims from STS1 token?
Generally you will only want to utilize one token at each step. So if you need to merge up claims, you will want to do that at the claims transformation step of the second STS.
So the flow would be authenticate with STS1, then authenticate with STS2 with the token from STS1. At that point you would pass through the claims and transform to add additional claims as needed. Then the resulting Token would be ready to consume from the RP application.
I have actually started a blog series about a really similar scenario that we recently architected. Not to be overly self promoting, but it doesn't make me any money, so I'll post it in case it is helpful.
http://www.livingthearchitecture.com/mixing-sso-with-existing-technologies/
I would be glad to go more in depth, but depending on the specifics of your scenario, the specifics of the solution will change greatly. I think the above expresses the general approach you will want. Let me know if I can help any more.

How does AntiForgeryToken work behind the scenes?

I know the basics of CSRF and AntiForgeryToken.
I also know that there are many similar questions around but none seemed to describe the implementation details, which is the part I'm interested in.
Each time you call Html.AntiForgeryToken(), it generates a new random token :
Can I have multiple active tokens at the same time? (I assume it's yes here)
Can I use any of those tokens in another form? (I assume it's yes here)
Can I use the same token more than once?
Is there a security reason why the token is random everytime? Couldn't it be the same token for the whole session?
The token is stored in a cookie
When I have multiple forms and tokens in my page, does it mean I have multiple cookies or only 1 cookie containing all the active tokens?
Also...
How is the token generated and is it possible to validate it manually.
1.Can I have multiple active tokens at the same time? (I assume it's yes here)
-> Yes.
2.Can I use any of those tokens in another form? (I assume it's yes here)
-> Yes.
3.Can I use the same token more than once?
-> Short answer is yes you can. Long answer: It depends on multiple factors, you would have to regenerate the token if,
Your cookie expires
Your user identity has changed.
Your additional data provider has decided that your token is no
longer valid.
4.Is there a security reason why the token is random every time? Couldn't it be the same token for the whole session?
-> You don't want anyone to be able to predict your token. Remember there is no inbuilt auto expiration of the cookie token.
1.When I have multiple forms and tokens in my page, does it mean I have multiple cookies or only 1 cookie containing all the active
tokens?
-> At any given point of time there would be only one cookie that will be active for a session,
that cookie has a SecurityToken property. Every valid anti-forgery token on the page would have the same SecurityToken (otherwise it would fail validation).
1.How is the token generated and is it possible to validate it manually.
I would suggest to read the post explaining the internals here
and code here
I am actually thinking why would you need to use the same anti-forgery token across forms.. it might be helpful if you share your scenario.
For you last question, you can validate AntiForgeryTokens with the following:
System.Web.Helpers.AntiForgery.Validate(cookie.Value, formValue);
Answering in terms of ASP.NET Core just in case anyone stumbles upon this post from Google.
The following is based off this article:
Can I have multiple active tokens at the same time?
Yes. If you have two tabs open and hit the same URL that returns to you a page with a form containing an antiforgery token, you'll have a different token in the HTML on each page. But you'll have the same token in your cookie.
Can I use any of those tokens in another form?
Yes. You can test this by hitting the URL in two tabs, open Developer Options and swap out the tokens, and the application won't know any better.
Can I use the same token more than once?
Yes. As long as the token in the HTML was generated along with your cookie, then if you're using the same cookie, you could use the same token in your HTML as before.
Is there a security reason why the token is random everytime? Couldn't
it be the same token for the whole session?
See the accepted answer by Harsh Gupta.
When I have multiple forms and tokens in my page, does it mean I have
multiple cookies or only 1 cookie containing all the active tokens?
See the accepted answer by Harsh Gupta.
How is the token generated and is it possible to validate it manually.
Here is a summary from the article I linked above:
Build a byte array using a random number generator.
Generate a unique array based on step 1.
Encrypt the array.
Prepend a magic header and the defaultKeyId to the encrypted array.
Base64URL encode the encrypted array and use this as the token
string.

How to transparently renew the Facebook access token while processing a service method which uses Facebook API calls?

I have a WCF service which runs in IIS 7.5 and VS 2010. This service has some methods which internally use the Facebook C# SDK (version 4.1, not latest) in order to perform some GET and POST from/to Facebook. Since Facebook will soon remove the offline_access I have to handle the situation where an access token is expired.
I have understood the way the authentication is performed (in order to get the code and after having the code to get the access token) in order to use the Graph API for getting Facebook information (as presented here).
I have two questions:
When my service method is called and I retrieve the token of the
appropriate user from my DB, is there a way to know if the access token
is expired or not? I have read that when a Facebook API call is performed and the access token is expired then the following exception is thrown: OAuthException. But is there any better way to detect the expiration? I don't want to
Call the Facebook API
Handle the exception
Renew the access token and finally
Repeat the initial call with the new access token.
Is it possible to renew the access token of the user transparently (store it also in the DB) and continue to handle the service method?
In this resource, the important ("Renewing an Access Token") part is missing (declared as
[todo])
I would like to achieve the following scheme, in the implementation of the Service Method:
sc = SocialNetworkAccountDao.GetByUser(user)
isExpired = call method to check if the sc.token is expired.
if (isExpired)
{
newToken = call method for getting new access token
sc.token = newToken;
SocialNetworkAccount.Update(sc);
}
Facebook = new Facebook (sc.token)
Facebook.Post( ..... )
--
The process to communicate with the QAuth dialog is asynchronous (a redirect is performed), and the communication with access token url to get the access token this is performed synchronously.Final Question:
Is there a way the service method to wait for the new access token we
retrieve from the request / callback with Facebook in order to
continue later with the new access token?
I don't know about the C# SDK, but ALL facebook SDKs are basically just wrappers for http request to the graph different urls.
If you use the server side authentication flow then you should get a long lived token (about 60 days), and you get the expiration time with it, when it expires you need to re-authenticate the user, there's no way to extend the token.
The client side authentication returns a short lived token (about 2 hours) but you can use the new endpoint facebook provided to replace the "offline_token".
You can only use that with still valid access tokens.
Also, no matter what, you always get the "expires" time when you get an access token, unless it's an application token which does not have an expiration date.
In either case, if you get a long lived token you can store it in the database and use it on the server side, but be aware that the token can still get invalidated for a number of reasons.
You can also use the official documentation for Handling Invalid and Expired Access Tokens.
If the C# SDK doesn't work well for you then you might want to just implement it yourself, for your own needs, should be pretty easy.
You should really update the c#sdk to the latest version - they fix a lot of issues over time..
Renewing a token
This is our code that handles the renew call itself (c#sdk ver 6.0.16, but this should work on earlier versions as well):
/// <summary>
/// Renews the token.. (offline deprecation)
/// </summary>
/// <param name="existingToken">The token to renew</param>
/// <returns>A new token (or the same as existing)</returns>
public static string RenewToken(string existingToken)
{
var fb = new FacebookClient();
dynamic result = fb.Get("oauth/access_token",
new {
client_id = FACEBOOK_APP_ID,
client_secret = FACEBOOK_APP_SECRET,
grant_type = "fb_exchange_token",
fb_exchange_token = existingToken
});
return result.access_token;
}
Facebook says that the new token may be the same (but extended expiration) or a completely new one, so you should handle that in your logic if required.
According to Facebook, you should call the renew up to once a day. (https://developers.facebook.com/roadmap/offline-access-removal/)
We keep a time-stamp on when the last 'Facebook update' was done, and if that time is over 24h ago and the user is accessing our application, we go in the background and renew the token. (we also update other data, name, email and other things we need)
Apparently, it is not calling it up to once a day, but calling it once per token.
Facebook will not let you renew a longed-live token. See 'Scenario 4:' at the offline access removal page
To clarify: short-lived tokens come from clients, long-lived tokens come from server-side.
In short, when a user access your app, use the SDK of the client to get a new short-lived token send it to the server, and extend it with your server to make it a long-lived and store that, so you get 60 days from that point.
Handling the Expired time
In our current usage, we were not required to keep the track of expire time, as all access starts with a client that checks that, but in the same the code access result.access_token it can access result.expires which returns the number of seconds remaining on that newly acquired token (should be close to 5 mil => 60 days)).
In any case, I am not sure there is a way to get the expire time from a token without making another call to the auth process. I know that the Facebook Debugger returns this, but that does not really helps..
Renewing an invalid token
This will not work, you will get any of the errors as explained here when trying to renew an expired/invalid token.
Remember to call the renew before it expires and remember that when you call renew on an expired (or any other kind of invalid) you will get an error and need to handle it (we handle it outside the code I pasted).
Time till expire
Short answer: you get the seconds until it expires, but the c# api appears not to expose it.
According to this facebook documentation, you get the the number of seconds until the token expires as a paramater when you get the token. The documentation lists the response format as :
access_token=USER_ACESS_TOKEN&expires=NUMBER_OF_SECONDS_UNTIL_TOKEN_EXPIRES
This is backed up by the the draft RFC for Ouath 2 which says responses should contain the expire time.
Unfortunately, it is directly contradicted by the C# SDK documentation that states here that
There is no way to determine if an access token is expired without making a request to Facebook. For this reason, you must always assume that an access token could be expired when making requests to Facebook.
This is not true. If you look at the c# SDK source, the object the sdk creates for the OAuth response explicitly contains ( unfortunately as a private variable) the following code
/// <summary>
/// Date and Time when the access token expires.
/// </summary>
private readonly DateTime _expires;
So it has the data, but for some reason does not expose it ( at least there, I didn't look to much further). I'd say either dig around the library more and see if its exposed somewhere, fork and patch it on github(i believe it's a one line change), or use reflection to read the private variable in your own code.
Continuing to handle the service method and renew token
Short answer: Maybe.
If you knew the token was expired, you could obviosuly get a new one before the request.
If you don't, than you kinda can, but you need to handle your request failing. In theory, this doesn't mean you need to handle an exception, just look at the http status code (which will be one in the 400s probably 403 forbidden ) however C#'s webrequest method interpets non 200 status c as events that raise an exception. Since the API uses this mechanism to make calls, you only get an exception when they fail.
Is there a way for the service method to wait for the new access token we retrieve from the
Sure, after you handle the exception.
Once this happens, asynchronously, you will get a new auth token. So you can, after catching the exception, wait some amount of time,check if you get a new token for that user, and if so retry . If keep waiting and checking. Make sure you have a maximum number of retries and a maximum amount of time to wait. Pulling the database to check for changes is a little inefficient, so you probably want to pick the time interval you check for changes on carefully and potentially make it exponentially back off.
The other, more efficient (for a single server), but complex way, is to have the system that gets the callback with the auth token raise events and have the retry logic listen for those events.
When your code gets an exception because your token is expired, in the catch block make a function that will redo the request and then add it as an event listener to the auth events. Have the function check that the event was for a fresh auth token for the users who request the event and if so, make the request. Again, remember to have a maximum retry count.
It is not possible to actually use async/await or something like that to wait for your request for a new token to cmplete. The problem, refreshing the API token is not request that you can wait on the response for , its actually triggering something that eventually causes a seperate get request to be made
Note, although the above diagram is for when a user first logs in, the same sequence happens roughly on a failed call, but it starts with the redirect.

Categories