What's the best way to ask for a password?

⚓ Rust    📅 2026-03-04    👤 surdeus    👁️ 3      

surdeus

I always wondered how to hide stdin, and now I came across a solution: stty -echo. This just stops keystrokes from being printed. Very simple! Naturally, I had to try it in Rust:

use std::{
    error::Error,
    process::Command,
    io::{self, BufRead},
};

fn main() -> Result<(), Box<dyn Error>> {
    println!("\nEnter password:");

    // Hide stdin
    assert_eq!(
        Command::new("stty")
            .arg("-echo")
            .spawn()?
            .wait()?
            .code()
            .unwrap(),

        0
    );

    let mut buf = String::new();
    io::stdin()
        .read_line(&mut buf)
        .unwrap();

    println!("Your password was `{}`", buf.trim());

   // Reset terminal
     assert_eq!(
        Command::new("stty")
            .arg("echo")
            .spawn()?
            .wait()?
            .code()
            .unwrap(),

        0
    );

    Ok(())
}

This works as expected, and prints:

Enter password:
        // User typed `Hello, world`, but it is hidden
Enter password:
Your password was `Hello, world`.

However, I didn't like the fact that the password is typed on a different line, so I tried to make it so that the (hidden) password is typed directly after the Enter password: prompt, like how sudo does it.
Like so:

use std::{
    error::Error,
    process::Command,
    io::{self, BufRead},
};

fn main() -> Result<(), Box<dyn Error>> {
    print!("\nEnter password:");

    // Hide stdin
    assert_eq!(
        Command::new("stty")
            .arg("-echo")
            .spawn()?
            .wait()?
            .code()
            .unwrap(),

        0
    );

    let mut stdin = io::stdin().lock();
    let mut buf = Vec::new();

    stdin.read_until(b"\n"[0], &mut buf)?;

    println!("Your password was `{}`", String::from_utf8(buf)?.trim());

   // Reset terminal
     assert_eq!(
        Command::new("stty")
            .arg("echo")
            .spawn()?
            .wait()?
            .code()
            .unwrap(),

        0
    );

    Ok(())
}

This should read stdin after the prompt, and stopping when a newline is reached.
However, it produces this strange output:

        // No prompt, but stdin is being consumed. User types `Hello, world` and it is hidden

Enter password:Your password was `Hello, world`

I imagine this is a somewhat unavoidable issue caused by stty hiding the whole line or something.

Is there any way to achieve this?

Any help is appreciated. Thanks!

5 posts - 5 participants

Read full topic

🏷️ Rust_feed