Curl POST With Basic Authentication Example

A POST with Basic authentication is two separate things in one command: a header that identifies you and a body that carries the data. Knowing they are independent is most of what there is to debugging one.

Last updated . How this page is checked.

The command

curl -u ada:s3cret https://httpbin.org/post \
  -H "Content-Type: application/json" \
  -d '{"name":"report","format":"pdf"}'

Opens the request console with this request filled in. It is sent from api-tester.com's server rather than from your machine, so it shows what the endpoint returns, not how your own network or curl build behaves.

What the flags do

FlagWhat it does
-u user:passwordAdds the Authorization: Basic header and changes nothing else.
-d dataThe body. Its presence is what makes the request a POST.
-H "Content-Type: ..."Describes the body. Unrelated to the credentials.
-iPrints the status line, the quickest way to tell which half failed.

Which half failed

Servers check the header before they look at the body. A 401 therefore tells you nothing about your data: it was never parsed. A 400, 415 or 422 means the opposite, that the login was accepted and the complaint is about the body or its Content-Type. Fix whichever half the status code points to and leave the other alone.

The body can be any kind. Here the same credentials accompany ordinary form fields instead of JSON.

curl -i -u ada:s3cret \
  -d "title=Q3 report" -d "visibility=private" https://httpbin.org/post

The one you will meet most: an OAuth token request

The commonest real POST with Basic authentication is the OAuth client-credentials grant. The client id and client secret go in -u, the grant type goes in a form body, and the response is a JSON document containing an access token for later requests. If the secret contains characters such as +, / or % and the server rejects it, the specification's rule is that both values are URL-encoded before curl sees them.

curl -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d "grant_type=client_credentials" -d "scope=orders.read" \
  https://auth.example.com/oauth/token

When the scheme is not Basic after all

With Basic, curl attaches the header up front and the POST happens in one request. Challenge-based schemes take two. With --digest curl knows the first attempt will be refused, so it sends that one with an empty body and transmits your data only on the second, authenticated request. With --anyauth it cannot know in advance and sends the full body both times, which fails for data piped in from standard input because a pipe cannot be read twice.

curl --digest -u ada:s3cret -d "title=Q3 report" https://api.example.com/reports
curl --anyauth -u ada:s3cret --data-binary @report.json https://api.example.com/reports

Common mistakes

  • Username and password as body fields is a different mechanism. A website login form reads them from the body and answers with a cookie; it ignores -u entirely.
  • A successful login says nothing about the write. If the request times out, check whether the record was created before posting it again.
  • Over plain HTTP both halves are exposed: the password and the data travel readable by anyone on the path.

Related curl examples

More under Authentication

References

These links leave api-tester.com, which is independent of the projects they point to.

FAQ

How do I send a POST request with Basic authentication in curl?

Combine -u username:password with a body flag, for example curl -u ada:s3cret -d "name=report" URL. Curl adds the Authorization header and sends the data as the POST body.

Do the username and password go in the POST body?

No. With Basic authentication they travel in the Authorization header. Only login forms expect credentials as body fields.

How do I POST JSON with Basic auth in curl?

Add -u username:password to a JSON POST: curl -u user:pass -H "Content-Type: application/json" -d '{"key":"value"}' URL.