How to pass password with special characters to RPC API via curl? When I set a simple password in my .conf file

rpcuser=user
rpcpassword=password


I can contact my wallet using curl from the command line like so:

$ curl --verbose --user 'user:password' --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "getbalance", "params": [] }' -H 'content-type: text/plain;' http://127.0.0.1:18332/
*   Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 18332 (#0)
* Server auth using Basic with user 'user'
&gt; POST / HTTP/1.1
&gt; Host: 127.0.0.1:18332
&gt; Authorization: Basic dXNlcjpwYXNzd29yZA==
&gt; User-Agent: curl/7.50.1
&gt; Accept: */*
&gt; content-type: text/plain;
&gt; Content-Length: 74
&gt; 
* upload completely sent off: 74 out of 74 bytes
&lt; HTTP/1.1 200 OK
&lt; Content-Type: application/json
&lt; Date: Τετ, 21 Ιούν 2017 08:59:30 GMT
&lt; Content-Length: 52
&lt; 
{"result":14.13139559,"error":null,"id":"curltest"}
* Connection #0 to host 127.0.0.1 left intact


But if I set a more complex password with special characters, such as

rpcuser=user
rpcpassword=!@#$%^&amp;*()


then the call fails with 401 - Unauthorized

$ curl --verbose --user 'user:!@#$%^&amp;*()' --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "getbalance", "params": [] }' -H 'content-type: text/plain;' http://127.0.0.1:18332/
*   Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 18332 (#0)
* Server auth using Basic with user 'user'
&gt; POST / HTTP/1.1
&gt; Host: 127.0.0.1:18332
&gt; Authorization: Basic dXNlcjohQCMkJV4mKigp
&gt; User-Agent: curl/7.50.1
&gt; Accept: */*
&gt; content-type: text/plain;
&gt; Content-Length: 74
&gt; 
* upload completely sent off: 74 out of 74 bytes
&lt; HTTP/1.1 401 Unauthorized
* Authentication problem. Ignoring this.
&lt; WWW-Authenticate: Basic realm="jsonrpc"
&lt; Date: Τετ, 21 Ιούν 2017 09:03:05 GMT
&lt; Content-Length: 0
&lt; Content-Type: text/html; charset=ISO-8859-1
&lt; 
* Connection #0 to host 127.0.0.1 left intact


It doesn't seem like the password was mangled at the shell level. It was passed verbatim.

$ echo dXNlcjohQCMkJV4mKigp | base64 -d
user:!@#$%^&amp;*()


There must be a way to do this, because bitcoin-cli works with the complex password just fine.

$ bitcoin-cli getbalance
14.13139559


Looking into bitcoin-cli.cpp it seems the client is using basic HTTP auth, which is consistent with what the wiki says.

strRPCUserColonPass = GetArg("-rpcuser", "") + ":" + GetArg("-rpcpassword", "");


...and later on...

evhttp_add_header(output_headers, "Authorization", (std::string("Basic ") + EncodeBase64(strRPCUserColonPass)).c_str());


Can someone please figure this out for me?

I want to know because I'm trying to pass complex passwords into EasyBitcoin-PHP and failing.

Thanks.
It seems that this is a bug in Bitcoin Core. I will take a look at it.

Edit:
I see the problem now. You have # in your password. The config file parse will interpret # as the beginning of a comment. So this means that it thinks the rest of your password is considered a comment by the config file. You cannot use # anywhere in the config file or everything after it will be interpreted as a comment.

In your example, the rpcpassword that Core is using is !@. To have # in your rpcpassword, I think you will actually need to use the rpcauth option which uses hashes instead of putting the password string in the config file.