I have a number of tasks running concurrently making asynchronous web requests. They all reference a header string which contains an authorisation token required to make a successful request. After some duration the token expires and a new one must be generated for future web requests to work. To do this, each Web Request has a fallback where if it returns an unauthorised error it will send off a new token request and then apply that to the global token string, and then re-run the request.
Imagine I have Tasks A & B performing asynchronous requests. They both receive an unauthorised request error and attempt to generate a new token, however Task A received it before Task B and so has already began the request for a new token.
What would be the best way to ensure the entire operation is thread safe? So that when Task B goes to request a token it realises that Task A is already in the process of doing so, so Task B no longer attempts to send of a token request, but simply waits for Task A to finish and return a value that they both can use.
I thought of simply using a lock, but Task B would only wait to re-generate the token itself and not realise that it can use the recently regenerated value of Task A.
I got around this simply by utilising a lock. I was vastly overthinking my initial approach.
Related
I hope this perhaps isn't too generic of a question. In gatewayAPI based microservices architecture pattern in .net - is it possible for a method dressed with [AllowAnnonymous] to call a method from another microservice that is dressed with [Authorize]?
The challenge that I have is that I have a payment processing method, which posts to another microservice to send an email confirmation, but the email method is marked authorized, and payment one is not.
Yes.
Think of it in terms of who is making the request.
A user makes a request to your endpoint, if there's any authorization, it's processed against the user's session token, form data, other cookies, etc that were included in the request by the user's browser.
If your code spins up an HttpClient and sends a request, the 'user' in this case is your server. If authorization is required, you'll need to include that in the HttpRequestMessage. What that looks like exactly depends on the endpoint you're hitting.
I have Web API.
Authorization is made via token from 3rd party API.
If request comes i check is token set -> if not, get it, set and use.
If response is 401 i need to try refresh token and then call API.
How to make it thread safe way and make other requests wait until failed one retries?
Request -> if token set -> use token, make request -> if response 401 -> try refresh token, make request one more time -> if failed, die.
All threads should use same token and not try to refresh it when some other thread already tries to do it.
In our application, we periodically encounter a scenario where the user requests a new token at the same time when we're automatically refreshing the token in the background (via JS.)
Both requests are using the refresh token & hitting the token endpoint.
If the automatic request finishes first, the user-initiated request results in an error. This is because both requests are trying to use the same refresh token but since it can only be used once, it's consumed by the first request and the second request gets 400 Bad Request.
My question is: What's the best way to handle the 400 response for the second request? Ideally, I want to silently retry the request and the user should be none-the-wiser.
If this occurs, the ultimate fall-back has to be reauthenticating - IdentityServer is doing nothing wrong, the ball is in your court.
But - you should be able to make this situation impossible by synchronising the automatic token refresh and the user-driven token request. If the refresh token lives in your application in one place, then you can regulate access to it via some kind of lock/release mechanism.
This npm package looks like it'd do it: https://www.npmjs.com/package/lock
Alternatively you could synchronise calls on the server by subclassing the relevant IdentityServer component, and using a per-client lock there - but IdentityServer is already complicated, it would require many locks in one place, and it wouldn't be easily scalable to multiple server instances.
I’m writing a web api that will be called from a background service to fetch some data. After some research I decided to use a Json web token to achieve that but I’m still a bit confused regarding when a new token should be requested.
Let’s say I start up my service, I request a token, the token expires after 15 minutes, then after 20 minutes I make an api call with the expired token. I will get an unauthorized error or something.
My question is: How will the client know when to request a new token? Should it request a new one before every api call? Seems like I’m missing something. Maybe I should make the token permanent and store it in the database?
Thanks
The answer to this is slightly application specific, but the OAuth specification has a mechanism for "refresh tokens", which can be used to grant new "access tokens" (the token typically included on each API request), without having to send the user to the UI authentication process to have them re-authenticate. So, once you request an access token, you will receive a refresh token and an access token. This methodology allows access tokens to be used for much shorter time frames.
This can also be done without refresh tokens, but in those cases the access token timeout would likely be longer, and then you would request that the user re-authenticate through the usual OAuth UI process. Note that even when you do have refresh tokens, the refresh token can also be set to expire, in which would then require a user re-authentication through UI again.
In some API's you just make the API request as usual, and if you get a response that is defined by the API to be one that indicates the access token has expired, you can then issue an API call to refresh the token (or fully request a new one if that is expired, or you the API doesn't have refresh tokens), and then make the original API call again with the new access token.
The API can also have a response that includes the timeout or expiration date/time of the access token as well. Then, the client can avoid sending the initial API call first, and simply send the refresh token call first.
In implementing your API, you could likely use any of these methodologies.
Here's some general discussion on the OAuth spec website, to provide more depth:
https://www.oauth.com/oauth2-servers/making-authenticated-requests/
https://www.oauth.com/oauth2-servers/access-tokens/access-token-lifetime/
https://www.oauth.com/oauth2-servers/access-tokens/refreshing-access-tokens/
And also, here's an example from the Twitter API regarding response codes showing one of the access token expiration techniques (see the "Error Codes" section, under error code 89, which implies the token has expired and you need to get a new one):
https://developer.twitter.com/en/docs/basics/response-codes
Since your client is background service , you can use the Oauth2 Client Credential Flow . Your background service can request an access token using only its client credentials when the client is requesting access to the protected resources under its control.
With this flow , you does't need to care much about the token expires , if client sends an expired token to web api , web api validate the token and create token expires response to your service , your service check the status code/response , directly send a new token request to web api to get new access token , there is no need to use refresh token which uses in other flows .
The fact is that your harness should be prepared to request any token when getting an Unauthorized status code. What I do in test is to check the expiration datetime, if close enough I refresh or get a new token whatever applies to your Auth. Also when getting an unauthorized status code my code does a refresh once and keep a count. If I get another unauthorized code then I return a false or throw an exception after I log the error on the second try. This works fine for me.
I have a WebAPI service that uses ADFS (not important to the question but it's microsoft's active directory authentication service).
A user sends a request to the server and since he isn't authenticated he is redirected to the ADFS's login page. Next time he sends a request to the server he will send an authentication cookie which will allow him to skip the ADFS login page.
The service is being accessed by a different domain (CORS) but I already fixed that issue. GET request are processed easily.
My problem is with OPTIONS requests, since my service is a on a different domain then the website's domain. An OPTIONS request is sent before each POST request. All OPTIONS requests do not include cookies so the request is being redirected to the ADFS login page.
I wanted to create a message handler which will execute even BEFORE the ADFS, Like a message handler that will be the very first code which will run of the message so I could check if the method of the request is OPTIONS (in which case I will simply return a response)
I tried using an example I found on message handling but it's being executed too late, the ADFS' message handler is way above it
public class MessageHandler2 : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
// Create the response.
var response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent("Hello!")
};
// Note: TaskCompletionSource creates a task that does not contain a delegate.
var tsc = new TaskCompletionSource<HttpResponseMessage>();
tsc.SetResult(response); // Also sets the task state to "RanToCompletion"
return tsc.Task;
}
}
Does anyone know how can I handle a message as high up the pipe as possible? Maybe even without message handlers
If you take a look at the following tutorial...
HTTP Message Handlers in ASP.NET Web API
You will see...
Message handlers are called in the same order that they appear in
MessageHandlers collection. Because they are nested, the response
message travels in the other direction. That is, the last handler is
the first to get the response message.
You need to make sure you register your handler before ADFS. Take a look at your setup for your web api