648

I want to access a URL which requires a username/password. I'd like to try accessing it with curl. Right now I'm doing something like:

curl http://api.somesite.com/test/blah?something=123

I get an error. I guess I need to specify a username and password along with the above command.

How can I do that?

22 Answers 22

934

Use the -u flag to include a username, and curl will prompt for a password:

curl -u username http://example.com

You can also include the password in the command, but then your password will be visible in bash history:

curl -u username:password http://example.com
17
  • 144
    Note that if you do this from the console the password will remain in the history which is ... wrong. You should specify just -u user and CURL will ask you for the password in no-echo mode. Commented Apr 19, 2013 at 22:44
  • 29
    @CristianVrabie Technically correct, but incorrect if you're running it from an automated script that doesn't allow prompts. Would be curious about a solution to that problem.
    – akahunahi
    Commented Mar 12, 2014 at 23:29
  • 32
    @OmarOthman if you're running curl from a script, the credentials (obviously) won't end up in your history, but they'll be visible in ps(1). fix: print -- '-u username:password' > somewhere && curl -K somewhere http://... Commented May 22, 2014 at 10:10
  • 9
    @Jay Environment variables will be evaluated before command execution. Password will be still visible in ps output. Commented Apr 11, 2016 at 11:04
  • 18
    Not to belabor the point but I believe my answer (stackoverflow.com/a/27894407/758174 i.e. using --netrc-file) is more secure. It keeps the password out of history, ps, your script, etc. That is the only form I use in all my scripts and for all authenticated usages of curl.
    – Pierre D
    Commented Jul 12, 2016 at 19:12
362

It is safer to do:

curl --netrc-file my-password-file http://example.com

...as passing a plain user/password string on the command line, is a bad idea.

The format of the password file is (as per man curl):

machine <example.com> login <username> password <password>

Note:

  1. Machine name must not include https:// or similar! Just the hostname.
  2. The words 'machine', 'login', and 'password' are just keywords; the actual information is the stuff after those keywords.
13
  • 12
    Yeah, that keeps the password out of the process listing and command history. Far preferable way to do this, and only a little more work :) Commented Apr 28, 2015 at 18:46
  • 9
    This should definitely be the accepted answer; passwords on the command-line are a horrible practice. (And this is a widely known fact.) Commented May 12, 2015 at 16:23
  • 7
    You can also use the flag -K <file> or --config <file> to receive curl flags via file or standard input. (Warning: not to be confused with -k or --insecure!)
    – Rufflewind
    Commented Apr 19, 2016 at 3:57
  • 2
    This curl method keeps credentials out of the history and process status, but leaves username and password in cleartext in the my-password-file creating another attack vector - worse than than having info in the history file: bash, for example, automatically restricts permissions of the history file. A similar problem arises if using environment variables with e.g. a script to set the username/password. If the script isn't secure, neither are the credentials. Commented Jan 9, 2017 at 19:39
  • 9
    @SteventheEasilyAmused I disagree, it's much better to use a cleartext .netrc file with appropriately strict permissions, so only your user can read it, than other mechanisms (e.g. command line args) that let other users read the information. Commented Oct 16, 2018 at 20:26
94

Or the same thing but different syntax

curl http://username:[email protected]/test/blah?something=123
8
  • 3
    I use that syntax, because can be used in a lot of more situations. Like from a Windows cmd with no cURL and no wGet, using start "" "http://username:[email protected]/test/blah?something=123". It can be launched from anywhere. That also applies to ftp logins ;D
    – m3nda
    Commented Dec 2, 2014 at 2:37
  • 12
    You need to URL encode the username & password to use funny characters Commented Jan 14, 2015 at 8:48
  • 2
    I know that most people know not to send passwords (or even user names) in the URL like this example as it is easy to sniff. With that said; I don't unrecommend it but use only when you know what you are doing.
    – LosManos
    Commented Feb 3, 2017 at 14:51
  • 3
    Unfortunately, this leaves the password visible in the process list.
    – Mark
    Commented Sep 7, 2019 at 20:42
  • 3
    @MarkRibau it does not show in the process list if you use the -u argument. neat trick from curl :-). see How does curl protect a password from appearing in ps output?
    – pjvleeuwen
    Commented Dec 11, 2019 at 13:28
69

You can also just send the user name by writing:

curl -u USERNAME http://server.example

Curl will then ask you for the password, and the password will not be visible on the screen (or if you need to copy/paste the command).

42

To securely pass the password in a script (i.e. prevent it from showing up with ps auxf or logs) you can do it with the -K- flag (read config from stdin) and a heredoc:

curl --url url -K- <<< "--user user:password"
5
  • 2
    Thanks for the reference to the --config option (-K)... possibly a better solution would be to put "--user user:password" into a file and simply -K the file so you have only one copy of the password rather a copy in every script. Much easier to secure a single file. Commented Oct 17, 2017 at 20:53
  • 1
    Similar option, where only the password is in the file: cat "${password_filepath}" | sed -e "s/^/-u ${username}:/" | curl --url "${url}" -K-. I had to put -K- before the url for old macOS bash, YMMV.
    – Mark
    Commented Sep 7, 2019 at 20:45
  • This looks like the idea solution for use with Jenkins. Commented Dec 11, 2020 at 14:34
  • No need to use sed if the password is in a file: echo "-u user:$(cat passwordfile)"|curl -K- url
    – Martin
    Commented May 23, 2022 at 11:47
  • 1
    @Martin - make the file ~/.netrc and use -n Commented Apr 14, 2023 at 13:42
21

Usually CURL command refer to as

curl https://example.com\?param\=ParamValue -u USERNAME:PASSWORD

if you don't have any password or want to skip command prompt to demand for password simple leave the password section blank.

i.e. curl https://example.com\?param\=ParamValue -u USERNAME:

1
  • 2
    NOTE: Password would be visible in shell history and process list.
    – Mark
    Commented Sep 7, 2019 at 20:47
14
curl -X GET -u username:password  {{ http://www.example.com/filename.txt }} -O
1
  • 3
    NOTE: Password would be visible in shell history and process list.
    – Mark
    Commented Sep 7, 2019 at 20:47
11

Other answers have suggested netrc to specify username and password, based on what I've read, I agree. Here are some syntax details:

https://ec.haxx.se/usingcurl-netrc.html

Like other answers, I would like to stress the need to pay attention to security regarding this question.

Although I am not an expert, I found these links insightful:

https://ec.haxx.se/cmdline-passwords.html

To summarize:

Using the encrypted versions of the protocols (HTTPS vs HTTP) (FTPS vs FTP) can help avoid Network Leakage.

Using netrc can help avoid Command Line Leakage.

To go a step further, it seems you can also encrypt the netrc files using gpg

https://brandur.org/fragments/gpg-curl

With this your credentials are not "at rest" (stored) as plain text.

1
  • Links are broken
    – AXMIM
    Commented Feb 11, 2022 at 15:46
11

pretty easy, do the below:

curl -X GET/POST/PUT <URL> -u username:password
2
  • 1
    There is no requirement of security on the question Commented Jun 20, 2019 at 21:31
  • 2
    NOTE: Password would be visible in shell history and process list
    – Mark
    Commented Sep 7, 2019 at 20:48
10

To let the password least not pop up in your .bash_history:

curl -u user:$(cat .password-file) http://example-domain.tld
2
  • 6
    In this case, the password will still end up in the process list, e.g. it is visible to somebody doing ps auxw |grep curl at the right time. Similarly, the password will be logged if run via sudo
    – Adam Katz
    Commented Nov 19, 2015 at 1:21
  • 1
    With this method the password is then present in a file (.password-file) which may be more insecure than the .bash history. The good part about this, is that it is only the password - the URL and username are not leaked in the .password-file. Commented Jan 9, 2017 at 19:44
8

I had the same need in bash (Ubuntu 16.04 LTS) and the commands provided in the answers failed to work in my case. I had to use:

curl -X POST -F 'username="$USER"' -F 'password="$PASS"' "http://api.somesite.com/test/blah?something=123"

Double quotes in the -F arguments are only needed if you're using variables, thus from the command line ... -F 'username=myuser' ... will be fine.

Relevant Security Notice: as Mr. Mark Ribau points in comments this command shows the password ($PASS variable, expanded) in the processlist!

3
  • 1
    Looks like this still shows the value of $PASS in the process list?
    – Mark
    Commented Sep 7, 2019 at 20:41
  • Yes, unfortunately it does.
    – Marco
    Commented Sep 7, 2019 at 20:57
  • I am getting curl: option -F: is badly used here. curl 7.58. What is your version?
    – jangorecki
    Commented Sep 22, 2020 at 10:27
6

You can use command like,

curl -u user-name -p http://www.example.com/path-to-file/file-name.ext > new-file-name.ext

Then HTTP password will be triggered.

Reference: http://www.asempt.com/article/how-use-curl-http-password-protected-site

2
  • link is broken.
    – Jason S
    Commented Jan 17, 2020 at 21:29
  • -p stands for --proxytunnel - misleading, but otherwise correct: "-u ... If you simply specify the user name, curl will prompt for a password." curl.se/docs/manpage.html Commented Apr 22, 2021 at 15:58
6

The safest way to pass credentials to curl is to be prompted to insert them. This is what happens when passing the username as suggested earlier (-u USERNAME).

But what if you can't pass the username that way? For instance the username might need to be part of the url and only the password be part of a json payload.

tl;dr: This is how to use curl safely in this case:

read -p "Username: " U; read -sp "Password: " P; curl --request POST -d "{\"password\":\"${P}\"}" https://example.com/login/${U}; unset P U

read will prompt for both username and password from the command line, and store the submitted values in two variables that can be references in subsequent commands and finally unset.

I'm gonna elaborate on why the other solutions are not ideal.

Why are environment variables unsafe

  1. Access and exposure mode of the content of an environment variable, can not be tracked (ps -eww ) since the environment is implicitly available to a process
  2. Often apps grab the whole environment and log it for debugging or monitoring purposes (sometimes on log files plaintext on disk, especially after an app crashes)
  3. Environment variables are passed down to child processes (therefore breaking the principle of least privilege)
  4. Maintaining them is an issue: new engineers don't know they are there, and are not aware of requirements around them - e.g., not to pass them to sub-processes - since they're not enforced or documented.

Why is it unsafe to type it into a command on the command line directly Because your secret then ends up being visible by any other user running ps -aux since that lists commands submitted for each currently running process. Also because your secrte then ends up in the bash history (once the shell terminates).

Why is it unsafe to include it in a local file Strict POSIX access restriction on the file can mitigate the risk in this scenario. However, it is still a file on your file system, unencrypted at rest.

2
  • 3
    It seems that this method would still show the password in the process list?
    – Mark
    Commented Sep 6, 2019 at 1:37
  • The other answer also miss to use the "read" command. That hits the essence I landed on this page. Why not add the follwoing line to your post: "read -p "Username: " U; curl -u "$U" <URL>; unset U"
    – BREMI
    Commented Mar 30, 2022 at 10:22
5

Plain and simply put the most secure way would be to use environment variables to store/retrieve your credentials. Thus a curl command like:

curl -Lk -XGET -u "${API_USER}:${API_HASH}" -b cookies.txt -c cookies.txt -- "http://api.somesite.com/test/blah?something=123"

Would then call your restful api and pass the http WWW_Authentication header with the Base64 encoded values of API_USER and API_HASH. The -Lk just tells curl to follow http 30x redirects and to use insecure tls handling (ie ignore ssl errors). While the double -- is just bash syntax sugar to stop processing command line flags. Furthermore, the -b cookies.txt and -c cookies.txt flags handle cookies with -b sending cookies and -c storing cookies locally.

The manual has more examples of authentication methods.

2
  • 1
    Bear in mind that using "-Lk" can open you up to man-in-the-middle (MITM) attacks, so use caution with that option.
    – GuyPaddock
    Commented Jul 2, 2017 at 13:55
  • 5
    This doesn't work... since bash expands those variables for you, the expansion appears in the process listing. Commented Oct 17, 2017 at 20:47
4

You can use gpg encrypted netrc file with curl like so:

netrc_file="$HOME/netrc.gpg"
curl --netrc-file <(gpg -d $netrc_file) https://...
4

In some API maybe it does not work (like rabbitmq).

there is alternative:

curl http://username:[email protected]

curl http://admin:[email protected]

also the above format is usable in browsers.

2

This is MUCH more than the OP asked for, but since this is a top result for securely passing passwords to curl, I'm adding these solutions here for others who arrive here searching for that.


NOTE: -s arg for read command is not POSIX, and so is not available everywhere, so it won't be used below. We will use stty -echo and stty echo instead.

NOTE: All bash variables below could instead be declared as locals if in a function, rather than unsetting.

NOTE: perl is pretty generally available on all systems I've tried due to it being a dependency for many things, whereas ruby and python are not, so using perl here. If you can guarantee ruby/python where you're doing this, you can replace the perl command with their equivalent.

NOTE: Tested in bash 3.2.57 on macOS 10.14.4. Some small translation may be required for other shells/installs.


Securely prompt a user for a (reusable) password to pass to curl. Particularly useful if you need to call curl multiple times.

For modern shells, where echo is a built-in (check via which echo):

url='https://example.com'
printf "Username: "
read username
printf "Password: "
stty -echo  # disables echoing user input, POSIX equivalent for 'read -s'
read pass
printf "\n" # we need to move the line ahead
stty echo   # re-enable echoing user input
echo ${pass} | sed -e "s/^/-u ${username}:/" | curl --url "${url}" -K-
unset username
unset pass

For older shells, where echo is something like /bin/echo (where whatever it echos can be seen in the process list):
THIS VERSION CANNOT REUSE THE PASSWORD, see lower down instead.

url='https://example.com'
printf "Username: "
read username
printf "Password: "
stty -echo  # disables echoing user input, POSIX equivalent for 'read -s'
perl -e '
    my $val=<STDIN>;
    chomp $val;
    print STDERR "\n";  # we need to move the line ahead, but not send a newline down the pipe
    print $val;
' | sed -e "s/^/-u ${username}:/" | curl --url "${url}" -K-
stty echo   # re-enable echoing user input
unset username



If you happen to need to store the password temporarily to a file, to re-use it for multiple commands before clearing it (say because you're using functions for code re-use and don't want to repeat code and can't pass the value around via echo). (Yes, these are a little contrived looking in this form not being functions in different libraries; I tried to reduce them to the minimum code needed to show it.)

When echo is built-in (this is especially contrived, since echo is a built-in, but provided for completeness):

url='https://example.com'
filepath="$(mktemp)"  # random path, only readable by current user
printf "Username: "
read username
printf "Password: "
stty -echo  # disables echoing user input, POSIX equivalent for 'read -s'
read pass
echo "${pass}" > "${filepath}"
unset pass
printf "\n" # we need to move the line ahead
stty echo   # re-enable echoing user input

cat "${filepath}" | sed -e "s/^/-u ${username}:/" | curl --url "${url}" -K-

rm "${filepath}"  # don't forget to delete the file when done!!
unset username

When echo is something like /bin/echo:

url='https://example.com'
filepath="$(mktemp)"  # random path, only readable by current user
printf "Username: "
read username
printf "Password: "
stty -echo  # disables echoing user input, POSIX equivalent for 'read -s'
$(perl -e '
    my $val=<STDIN>;
    chomp $val;
    open(my $fh, ">", $ARGV[0]) or die "Could not open file \"$ARGV[0]\" $\!";
    print $fh $val;
    close $fh;
' "$filepath")
printf "\n" # we need to move the line ahead
stty echo   # re-enable echoing user input

cat "${filepath}" | sed -e "s/^/-u ${username}:/" | curl --url "${url}" -K-

rm "${filepath}"  # don't forget to delete the file when done!!
unset username
1
  • "don't forget to delete the file when done" - Kiss of death, an error in the script could leave that file in the system. If you trust the "readable only by current user" then you should trust the .netrc file with rw only by the user. Commented Apr 14, 2023 at 13:49
2

If your server supports Basic auth, you could do:

printf 'header="Authorization: Basic %s"' "$(base64 --wrap=0 credentials)"|
curl --config - https://example.org

credentials would be the file where you store the username and password in the form username:password.

Benefits of this solution:

  • No escaping of special characters necessary
  • Works with any password, even when it contains spaces, quotation marks, backslashes or other special characters, therefore it can also be used securely in scripts where you don’t control the input
  • In shells with builtin printf, the login data does not show up in the process list

If your shell does not have printf as a builtin command, you could do something like this to avoid the login data appearing in the process list:

{ printf 'header="Authorization: Basic '; base64 --wrap=0 credentials; printf '"'; }|
curl --config - https://example.org
1

If you are on a system that has Gnome keyring app a solution that avoids exposing the password directly is to use gkeyring.py to extract the password from the keyring:

server=server.example.com
file=path/to/my/file
user=my_user_name
pass=$(gkeyring.py -k login -tnetwork -p user=$user,server=$server -1)

curl -u $user:$pass ftps://$server/$file -O
1
  • 4
    NOTE: Password would be visible in process list. (And history if this isn't part of a script.)
    – Mark
    Commented Sep 7, 2019 at 20:48
1

You should make sure what is the authentication type.

If it is digest authentication , http header is:

GET /xxxxxxxxxxx HTTP/1.1
Host: 192.168.3.142
User-Agent: Go-http-client/1.1
Authorization: Digest username="admin", realm="admin@51200304-49-test", nonce="5.1722929000077545", uri="/xxxxxxxxxxx", response="52d30eba90820f2c4fa4d3292a4a7bbc", cnonce="f11900fe0906e3899e0cc431146512bb", qop=auth, nc=00000001
Accept-Encoding: gzip

you can use --digest option :

    curl  --digest -u 'username:password' 'http://xxxxxxxxxxx'
1
  • 1
    Can you add why you would need the --digest option? Commented Dec 6, 2021 at 13:30
0

In my case I needed a prompt where the user can enter their credentials.

The most simplistic way to get a prompt for username and password would be the following one-liner:

read -p "Username: " U ; curl -u "$U" <URL> ; unset U

The read command prompts for the username. The -u "$U" parameter tells curl to try to authenticate with the username $U and prompt for the password.

As a bonus the password will only be visible to curl and won't end up in any log or history.

The man page of curl has more details about different authentication modes: https://curl.se/docs/manpage.html

I also like the approach the user "iammyr" takes. It can cover cases where the authentication algorithm of cURL fails:
https://stackoverflow.com/a/56130884/1239715

0

This has been mentioned in several comments....

% touch ~/.netrc
% chmod go-rwx ~/.netrc

Edit ~/.netrc using your "favorite editor" (apparently, if you don't use your favorite editor, it won't work and you won't cross the Bridge of Death) and add lines similar to:

machine  <machine name> login <login name>  password <password>

For example

machine  monty  login sirrobin  password african-swallow

This will keep the credentials out of command history and the process list, eliminate the need to enter the password by hand so your script can run autonomously, much simpler to use than having to specify a filename.

It does, however, leave the text in a file "at rest" (interesting term), so you have to rely on your system to enforce access restrictions (does that eliminate Windows?) and also expect that if root access (or your account) is compromised, then so is the content of .netrc.

The solutions that use gpg to decrypt an encrypted .netrc file push the credential requirement to gpg, so you have to be there when the script runs to provide the password or the password is provided by some other means, perhaps using a file similar to .netrc? ... and you have the same problem.

Not the answer you're looking for? Browse other questions tagged or ask your own question.