# Hide password input (Replace input with asterisk)

**URL:** <https://erlangforums.com/t/hide-password-input-replace-input-with-asterisk/3777>\
**Category:** Questions / Help\
**Tags:** erlang-otp\
**Created:** [June 23, 2024, 4:24pm UTC](https://erlangforums.com/t/hide-password-input-replace-input-with-asterisk/3777 "2024-06-23T16:24:16Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![0m3](https://erlangforums.com/user_avatar/erlangforums.com/0m3/32/2339_2.png) [@0m3](https://erlangforums.com/u/0m3)\
**Post date:** [June 23, 2024, 4:24pm UTC](https://erlangforums.com/t/hide-password-input-replace-input-with-asterisk/3777/1 "2024-06-23T16:24:16Z")

</div>

Hello, all.

How can I hide the user’s password input using asterisk?  
For example,  
To make it

```erlang
44> io:fread('Password> ', "~s").
Password> pwd
{ok,["pwd"]}

```

look like

```erlang
44> io:fread('Password> ', "~s").
Password> ***
{ok,["pwd"]}

```

I found 2 functions in the module `/path/to/otp//lib/stdlib/src/io.erl`

```erlang
 393 -doc false.                                                                                         
 394 get_password() ->                                                               
 395 get_password(default_input()).                                              
 396                                                                                 
 397 -doc false.                                                                     
 398 get_password(Io) ->                                                             
 399 request(Io, {get_password,unicode}).

```

```erlang
 45> io:get_password().

"pwd"
46> io:get_password(standard_io).

"pwd"

```

They do without an asterisk.  
There is no documentation on them here [stdlib/io](https://www.erlang.org/doc/apps/stdlib/io.html).  
Why are they missing from the documentation?

I also found that it is possible to disable `echo` using `io:setopts/1, io:setopts/2` functions.

---

<div class="post-metadata">

**Author:** ![starbelly](https://erlangforums.com/user_avatar/erlangforums.com/starbelly/32/209_2.png) [@starbelly](https://erlangforums.com/u/starbelly)\
**Post date:** [June 23, 2024, 5:01pm UTC](https://erlangforums.com/t/hide-password-input-replace-input-with-asterisk/3777/2 "2024-06-23T17:01:00Z")

</div>

It is undocumented for a reason, and so I would say use that function at your own risk 🙂

There are a few ways to get passwords while trying to hide input.

Here is one, which there problems with last time I tried, but it may be fine now :

```erlang
-module(test_password).

-define(OP_PUTC, 0).

-export([get_passwd/0]).

get_passwd() ->
    get_passwd("Password: ").

get_passwd(Msg) ->
    case io:setopts([binary, {echo, false}]) of
        ok ->
            PwLine = io:get_line(Msg),
            ok = io:setopts([binary, {echo, true}]),
            io:format("\n"),
            [Pw | _] = binary:split(PwLine, <<"\n">>),
            Pw;
        _ ->
            error_logger:tty(false),
            Port = open_port({spawn, "tty_sl -e"}, [binary, eof]),
            port_command(Port, <<?OP_PUTC, Msg/binary>>),
            receive
                {Port, {data, PwLine}} ->
                    [Pw | _] = binary:split(PwLine, <<"\n">>),
                    port_command(Port, <<?OP_PUTC, $\n>>),
                    port_close(Port),
                    error_logger:tty(true),
                    Pw
            end
    end.

```

This will fully hide input vs putting asterisks on the screen, there’s another issue with this, it will not work on windows iirc.

The other issue documented [here](https://github.com/erlang/otp/issues/4337) which either needs to be closed or a PR done (I never got around to doing it) was specifically related to escripts. I’m eager to try this again though, it’d be quite nice utilize this on windows.

`io:get_password/1` could be “fixed”, but I’m not sure the OTP team would be interested in this (documenting and supporting it).

If you are okay with a “it basically works” solution that works on all platforms, then you could go with what we currently do in rebar3\_hex (and mix hex as well) as seen [here](https://github.com/erlef/rebar3_hex/blob/9439eb28096464ba4fdc7e84c9df93c07c0aa785/src/rebar3_hex_io.erl#L45)

Edit:

Note that the `tty_sl` solution only works with OTP versions prior to OTP 26.

---

<div class="post-metadata">

**Author:** ![0m3](https://erlangforums.com/user_avatar/erlangforums.com/0m3/32/2339_2.png) [@0m3](https://erlangforums.com/u/0m3)\
**Post date:** [June 23, 2024, 5:13pm UTC](https://erlangforums.com/t/hide-password-input-replace-input-with-asterisk/3777/3 "2024-06-23T17:13:55Z")

</div>

Hello, @starbelly.

Thank you so much.

---

<div class="post-metadata">

**Author:** ![starbelly](https://erlangforums.com/user_avatar/erlangforums.com/starbelly/32/209_2.png) [@starbelly](https://erlangforums.com/u/starbelly)\
**Post date:** [June 23, 2024, 5:25pm UTC](https://erlangforums.com/t/hide-password-input-replace-input-with-asterisk/3777/4 "2024-06-23T17:25:51Z")

</div>

You are welcome, to note the `tty_sl` method won’t work for an escript still, it seems.

Edit:

`io:get_password/0/1` works in OTP 27. I wonder if this should be documented now 🙂

---

<div class="post-metadata">

**Author:** ![0m3](https://erlangforums.com/user_avatar/erlangforums.com/0m3/32/2339_2.png) [@0m3](https://erlangforums.com/u/0m3)\
**Post date:** [June 23, 2024, 5:50pm UTC](https://erlangforums.com/t/hide-password-input-replace-input-with-asterisk/3777/5 "2024-06-23T17:50:34Z")

</div>

Hello, @starbelly.

I was looking for information about tty\_sl.  
From here [The Beam Book/](https://blog.stenmans.org/theBeamBook/):  
_Erlang/OTP comes with a number port drivers implementing the predefined port types. There are the common drivers available on all platforms: `tcp_inet`, `udp_inet`, `sctp_inet`, `efile`, `zlib_drv`, `ram_file_drv`, `binary_filer`, `tty_sl`. These drivers are used to implement e.g. file handling and sockets in Erlang._  
From here `/path/to/otp/lib/kernel/src/user_drv.erl `

```erlang
   144 %% Backwards compatibility with pre OTP-26 for Elixir/LFE etc                   
   145 -spec start(['tty_sl -c -e'| shell()]) -> pid();                                
   146 (arguments()) -> pid().                                              
   147 start(['tty_sl -c -e', Shell]) ->                                                                                                                                                                            
   148 start(#{ initial_shell => Shell });                                         
   149 start(Args) when is_map(Args) ->                                                
   150 case gen_statem:start({local, ?MODULE}, ?MODULE, Args, []) of               
   151 {ok, Pid} -> Pid;                                                       
   152 {error, Reason} ->                                                      
   153 {error, Reason}                                                     
   154 end.                                                                        

```

What does it (`-c`, `-e`) stand for?

---

<div class="post-metadata">

**Author:** ![0m3](https://erlangforums.com/user_avatar/erlangforums.com/0m3/32/2339_2.png) [@0m3](https://erlangforums.com/u/0m3)\
**Post date:** [June 23, 2024, 5:53pm UTC](https://erlangforums.com/t/hide-password-input-replace-input-with-asterisk/3777/6 "2024-06-23T17:53:26Z")

</div>

Hello, @starbelly.

_`io:get_password/0/1` works in OTP 27._

Yes. I am using OTP 27.

---

<div class="post-metadata">

**Author:** ![starbelly](https://erlangforums.com/user_avatar/erlangforums.com/starbelly/32/209_2.png) [@starbelly](https://erlangforums.com/u/starbelly)\
**Post date:** [June 23, 2024, 5:55pm UTC](https://erlangforums.com/t/hide-password-input-replace-input-with-asterisk/3777/7 "2024-06-23T17:55:33Z")

</div>

Right, so it’s still use at your own risk (it could change, it could be removed, etc.), this won’t put asterisk in place ofc, but is a much better solution than either I shared above.

That said, I’m now interested in if it should be documented…

---

<div class="post-metadata">

**Author:** ![0m3](https://erlangforums.com/user_avatar/erlangforums.com/0m3/32/2339_2.png) [@0m3](https://erlangforums.com/u/0m3)\
**Post date:** [June 23, 2024, 5:59pm UTC](https://erlangforums.com/t/hide-password-input-replace-input-with-asterisk/3777/8 "2024-06-23T17:59:05Z")

</div>

Hello, @starbelly.

Thanks. Ok.  
What does it (`-c`, `-e`) stand for in `'tty_sl -c -e'`?

---

<div class="post-metadata">

**Author:** ![starbelly](https://erlangforums.com/user_avatar/erlangforums.com/starbelly/32/209_2.png) [@starbelly](https://erlangforums.com/u/starbelly)\
**Post date:** [June 23, 2024, 6:50pm UTC](https://erlangforums.com/t/hide-password-input-replace-input-with-asterisk/3777/9 "2024-06-23T18:50:01Z")

</div>

`-c` and `-e` should put the driver into non-canonical mode with no echo support. It also appears this driver was removed, and instead what you pasted from `user_drv` is for backwards compat and will now simply use the shell (which is an mfa, or mfargs if you want to be pedantic).

So, the tty\_sl solution I posted for will only work with version prior to OTP 26 I believe.

---

<div class="post-metadata">

**Author:** ![0m3](https://erlangforums.com/user_avatar/erlangforums.com/0m3/32/2339_2.png) [@0m3](https://erlangforums.com/u/0m3)\
**Post date:** [June 23, 2024, 7:11pm UTC](https://erlangforums.com/t/hide-password-input-replace-input-with-asterisk/3777/10 "2024-06-23T19:11:19Z")

</div>

Hello, @starbelly.

Ok. Thank you.
