Custom Auth Handler - HTTP Method and Body changes not functioning with re-direct

Hello, 

I've written a pretty basic Custom Authentication Handler to work with a vendor product we have deployed.  This product requires an HTTP request with a username/password to a specific web-endpoint which will generate an 'authentication token' that expires at a set time.  This authentication token is then passed with future requests which will authorize access to the services.  

I successfully have this working by setting the PreparedRequest "method" to POST and update the body to include the authorization token.  

I have been successful with this if I access a URL that does not have a re-direct.  Unfortunately I've stumbled across a few re-directs in the system, and it seems that my method overwrite (from get -> post) and including my token in the body of the request are lost on re-directs (these are not persisted with requests following the re-direct).  

I enabled IIS Failed Request Tracing on the server side to confirm this scenario.  I can see the following requests: 

**1st Request** - Generate the authentication token with username/password.  Successful HTTP 200 response with the token returned.  My Custom Auth Handler uses this token to update the PreparedRequest.body

**2nd Request** - Executed HTTP POST to the protected management console (that requires this token).  Server responds with an HTTP Status code 302 (re-direct) with a new location in the response header (in this case it just added a '/' at the end of the path).  I can see my authorization token in the request body

**3rd Request** - Requests does follow the re-direct, however it is re-converted back to an HTTP GET and my token (from the body) is also lost.  It does appear that my request headers did persist.  

Thoughts?  Thanks for any help!!!

Have you considered having the auth handler be stored on the Session object, and also have it do its own request creation to obtain auth tokens? Essentially, if it has an auth token it will just add it to all requests, and if it doesn't it will obtain one by making its own brand new request instead of by mutating the one the user is making?

Thanks for the feedback!

I will take a look at that.  Currently every request will generate another token passing the username/password every time (increasing the overall chatter).  The session enhancement should fix that issue as well.  

Since this posting... the code base was uploaded to: https://github.com/DOI-BLM/requests-agstoken

So, I've spent some time playing with requests Sessions and can confirm that my authentication handler works with that approach, however, I think there is still an issue to be discussed.  Here is the current control flow: 

- Developer creates an auth instance providing a username/password.  

- The auth instance is added to a request (or a session).  

- On the **first request**... the auth instance will execute its own request to the server 'get token' endpoint, provide the username/password and obtain the authorization token.  The auth instance will store the token and the date/time it expires (default is 60 min).  

- On all requests (first and subsequent), the auth instance will: 
    - Check token 'expires' timestamp and acquire a new one if needed
    - Change the PreparedRequest.method to POST
    - Add the token parameter to the PreparedRequest body

I can confirm that if I am accessing a URL that does not have a re-direct (HTTP 302), that everything works as expected.  The request is modified to a POST and the token is present in the body.  

If, however, there is an HTTP re-direct (302) then the requests API will follow the new **location** (defined in the response header), but the method gets set back to GET (if it was truly a GET originally), and the token is dropped from the body.  So I'm guessing there is an issue with re-directs not persisting the method and body changes of the request.  

So a couple questions...  

**Should it be a legitimate implementation approach to:**

1. **allow an auth handler to adjust the request body?** I looked through a couple of other auth handlers (like the HTTP Basic, NTLM and Kerberos handlers) and it appears those just modify request headers (www-authenticate).  I think yes.  If so, should this be classified as a bug?

2. **allow an auth handler to force the request method (for this example POST)?**  I could see this getting a little hairy, however HTTP POST requests are supposed to be more secure than HTTP GET requests (and in this case the token represents a users identity, hence the need to protect confidentiality of this data payload as best as possible).  

I might be able to register a response hook for HTTP 302 (or other re-directs) and possibly handle this scenario, if it is deemed that the underlying requests API will not be adjusted to account for this scenario.  

Thanks!










I'm not a contributor so feel free to take what I say with a grain of salt, but #3107 looks at the fact that POST gets changed to GET upon a HTTP 302 as that's what sending a 302 is telling requests to do, so that much is working as intended. You could always set `allow_redirects=False` in the request, capture the Location header yourself and then perform the new request. Or... get the server to return a 307/308 not a 302, as mentioned in #3107 

An auth handler is free to do *whatever it likes*. It can arbitrarily transform a request as it sees fit.

As to the redirect auth-stripping, I think that that is actually a separate bug: `requests.sessions.SessionRedirectMixin.rebuild_auth` should probably re-apply any auth handler that is present, which it currently does not.

Thank you all for the feedback.  

I've updated the code base (https://github.com/DOI-BLM/requests-agstoken) to handle re-directs.  I'm currently having problems with the vendor product recognizing my token in the body and had to revert to placing that in the URL query string (which I would rather not do since I know it is logged all over the server access logs).  This mimics the behavior I see in the vendor products management console (requests to the back-end 'admin' REST API are all HTTP GET with the token passed in a URL Query-String Parameter).  

At any rate, I think this is functioning well enough to start using in some operational tools.  I'll leave this issue open for another day or two in case someone wants to collaborate on this scenario, otherwise I'll close it. 

Thanks!!