1

I would like to authenticate against the Etrade API using Go and Postman. I am following the official Etrade API Developer Docs:

Etrade API welcome page

I successfully completed the Oauth 1.0 flow using the Python example they provided (with some slight modifications to print some of the session attributes):

$ python3 etrade_python_client.py

1)  Sandbox Consumer Key
2)  Live Consumer Key
3)  Exit
Please select Consumer Key Type: 2

Please accept agreement and enter verification code from browser: REDACTED
access_token_response: <Response [200]>
access_token: REDACTED
access_token_secret: REDACTED

But I have had no success authenticating using the Go or Postman implementations of Oauth 1.0. For Go, I wrote this sample client using the dghubble/oauth1 library, and for Postman I am using the built-in auth tool.

My trouble is largely with generating the correct oauth_signature in each of these. I always get this error:

invalid signature

Or if I try to plug-and-play the access token I obtained from Etrade's sample Python client into Postman when, for instance, accessing the /accounts/list API endpoint, the response I receive is:

<Error>
  <message>oauth_problem=signature_invalid</message>
</Error>

It's strange that their Python example (which uses rauth) has a different behavior than Go or Postman. Seems that Etrade does something non-standard that fits the requests.Session shape of the rauth implementation. Is there a way to know if I'm generating my signatures correctly for any implementation I use?

Appendix:

Sample Postman requests:

postman: request_token postman: auth url postman: access_token

Capture of session attributes when using Python rauth library (sensitive info redacted): https://gist.github.com/natemurthy/a7f628e44da9651d0676291803915c9c

Comparison of HTTP headers when calling /v1/accounts/list between Python vs Go:

Python:

GET https://api.etrade.com/v1/accounts/list.json

{'Authorization': 'OAuth realm="",oauth_consumer_key=REDACTED",oauth_nonce="22d0b83e4cba610148c990fdab1c327948a10677",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1668988571",oauth_token="REDACTED",oauth_version="1.0",oauth_signature="REDACTED"'}

Response: 200 OK

Go:

GET https://api.etrade.com/v1/accounts/list.json

map[Authorization:[OAuth oauth_consumer_key="REDACTED", oauth_nonce="eZ1twhwIs7f3wD90uOelpuNNAE2RZ8wkQm4gEKvlklM%3D", oauth_signature="REDACTED", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1669074040", oauth_token="REDACTED", oauth_version="1.0"]]

Response: 401 Unauthorized
{"Error":{"message":"oauth_problem=signature_invalid"}} 
nmurthy
  • 1,337
  • 1
  • 12
  • 24
  • I authenticated from C# which didn't use rauth, so special behavior seems unlikely. – BWhite Nov 15 '22 at 19:43
  • Can you use Postman to monitor your Python connection and see the difference? If it can't decrypt your SSL connection, try Fiddler to get the details and then put those into Postman. – BWhite Nov 15 '22 at 19:45
  • Yes, I've seen the C# examples work fine (e.g. https://stackoverflow.com/questions/62367417/e-trade-requesting-access-token-i-get-signature-invalid), but I don't have a deterministic way of creating a side-by-side comparison of the Python request and the Postman request (unless I can fix the nonce and timestamps in both requests to be the same) – nmurthy Nov 15 '22 at 22:01
  • A) Why do you care about getting it to work from Postman? B) Can you post the python and Postman requests as part of your question? We are not going to be much help if we can't see what we are working with. – BWhite Nov 16 '22 at 05:30
  • A) I mainly care about getting it to work with Go. Getting it to work with Postman is just to reproduce the behavior in a different client. B) I added some sample Postman screenshots in the "Appendix" above. Haven't had time to do a wireshark/tcpdump of the Python request, but I added a gist the shows the session attributes filled in from the rauth access_token step – nmurthy Nov 18 '22 at 01:15
  • My next step would be to monitor and compare the requests that are actually being sent using Fiddler and see what is different. I just had a case yesterday that I couldn't get sorted until I noticed in Fiddler that one was sending a GET and the other HEAD. ¯\_(ツ)_/¯ – BWhite Nov 18 '22 at 06:22
  • Looks like Fiddler is about $120/year. Worth it? https://www.telerik.com/purchase/fiddler – nmurthy Nov 18 '22 at 23:02
  • Fiddler Classic (Windows only) is free, or the 10 day trial. Either should be enough to solve your immediate problem. Beyond that, it would depend on how much you'd use it. – BWhite Nov 20 '22 at 06:49
  • I added a comparison of HTTP headers when calling `/v1/accounts/list` between the Python vs Go requests in the Appendix above. The only real difference I see is that the the latter request does not have `realm=""` set., which appears to be the _more_ correct thing to do according to RFC 5849 3.4.1.3 https://github.com/dghubble/oauth1/blob/main/auther.go#L226 – nmurthy Nov 21 '22 at 23:56

0 Answers0