Salesforce username/password OAuth flow against a sandbox

We had issues today because our OAuth password flow wouldn’t work against one of our sandboxes although the code worked against production. Instead we got this error:

{"error":"invalid_grant","error_description":"authentication failure"}

After Googling and finding this thread it turned out that when using the username/password flow against a sandbox you have to either relax IP restrictions for login or authenticate against test.salesforce.com instead of login.salesforce.com (which of course makes sense).

Below is curl commands for using the username/password flow against a sandbox:

$ curl -d "grant_type=password 
   &client_id=3MVG9X0_oZyBSzHrnzENlR...JSDz0_MiwxyieREuBhtgZJrF7Lzx8542TFpU_ 
   &client_secret=6235860963257688256 
   &username=mikkel.heisterberg%40example.com.sandboxname 
   &password=Passw0rd.SecurityToken" https://test.salesforce.com/services/oauth2/token
{"access_token":"00D6E000000Cpmu!AQ0AQIj4...cGCRqmNnYc6dmgLT09VNoIFXJtHvsPGLqrBs0VlK",
   "instance_url":"https://someaddress.my.salesforce.com",
   "id":"https://test.salesforce.com/id/00D6E000000CpmuUAC/0056E000000OCcCQAW",
   "token_type":"Bearer","issued_at":"1485850119972","signature":"malODIaSULh1siHzdw...pHKjBpWoQcm66UQ="}

$curl -H 'Authorization: Bearer 00D6E000000Cpmu!AQ0AQIj4...cGCRqmNnYc6dmgLT09VNoIFXJtHvsPGLqrBs0VlK' 
   https://test.salesforce.com/id/00D6E000000CpmuUAC/0056E000000OCcCQAW
{"id":"https://test.salesforce.com/id/00D6E000000CpmuUAC/0056E000000OCcCQAW",
   "asserted_user":true,"user_id":"0056E000000OCcCQAW","organization_id":"00D6E000000CpmuUAC",
   "username":"mikkel.heisterberg@example.com.sandboxname","nick_name":"mheis",
   "display_name":"Mikkel Heisterberg","email":"mheisterberg@foo.com","email_verified":true,"first_name":"Mikkel",
   "last_name":"Heisterberg","timezone":"Europe/Paris","photos":{"picture":"https://someaddress.content.force.com/profilephoto/005/F",
   "thumbnail":"https://someaddress.content.force.com/profilephoto/005/T"},"addr_street":null,"addr_city":null,"addr_state":null,
   "addr_country":null,"addr_zip":null,"mobile_phone":"+45 12345678","mobile_phone_verified":true,"status":{"created_date":null,
   "body":null},"urls":{"enterprise":"https://someaddress.my.salesforce.com/services/Soap/c/{version}/00D6E000000Cpmu",
   "metadata":"https://someaddress.my.salesforce.com/services/Soap/m/{version}/00D6E000000Cpmu",
   "partner":"https://someaddress.my.salesforce.com/services/Soap/u/{version}/00D6E000000Cpmu",
   "rest":"https://someaddress.my.salesforce.com/services/data/v{version}/",
   "sobjects":"https://someaddress.my.salesforce.com/services/data/v{version}/sobjects/",
   "search":"https://someaddress.my.salesforce.com/services/data/v{version}/search/",
   "query":"https://someaddress.my.salesforce.com/services/data/v{version}/query/",
   "recent":"https://someaddress.my.salesforce.com/services/data/v{version}/recent/",
   "profile":"https://someaddress.my.salesforce.com/0056E000000OCcCQAW",
   "feeds":"https://someaddress.my.salesforce.com/services/data/v{version}/chatter/feeds",
   "groups":"https://someaddress.my.salesforce.com/services/data/v{version}/chatter/groups",
   "users":"https://someaddress.my.salesforce.com/services/data/v{version}/chatter/users",
   "feed_items":"https://someaddress.my.salesforce.com/services/data/v{version}/chatter/feed-items",
   "feed_elements":"https://someaddress.my.salesforce.com/services/data/v{version}/chatter/feed-elements",
   "custom_domain":"https://someaddress.my.salesforce.com"},"active":true,"user_type":"STANDARD","language":"en_US","locale":"en_US",
   "utcOffset":3600000,"last_modified_date":"2017-01-26T13:49:33.000+0000","is_app_installed":true}