Golang Hide Password Input with x/term ReadPassword

Tested on RHEL 10.2 with Go 1.27.0
Package go 1.27.0
golang.org/x/term v0.45.0
Applies to Go 1.25+
Privilege Normal user
Scope Hide password input with term.ReadPassword, term.IsTerminal, non-TTY handling, and the difference between no-echo and asterisk masking. Does not cover authentication design or credential storage.
Related guides Golang os package
Environment variables in Go
Getting started with Go
Golang context

For a CLI that needs to accept a password without showing typed characters, term.ReadPassword from golang.org/x/term is the simplest approach. It reads one line from a terminal while disabling local echo, so the password is not displayed as the user types.

ReadPassword hides input completely. It does not automatically display ***** while typing.

Hiding input only affects terminal display; password hashing is a separate storage and verification concern.


Install golang.org/x/term

Pin the release tested in this article:

bash
go get golang.org/x/term@v0.45.0
output
go: downloading golang.org/x/term v0.45.0
go: downloading golang.org/x/sys v0.47.0
go: added golang.org/x/sys v0.47.0
go: added golang.org/x/term v0.45.0

The term package depends on golang.org/x/sys for platform-specific terminal control. golang.org/x/term v0.45.0 requires Go 1.25 or newer.


Hide password input with term.ReadPassword

The signature is func ReadPassword(fd int) ([]byte, error). Pass int(os.Stdin.Fd()) so you read from the same stdin handle your process uses.

Print the prompt before calling ReadPassword. ReadPassword does not echo the Enter key, so print a newline after the call to move subsequent output to the next line. The returned slice does not include the newline character.

Save this program as main.go:

go
package main

import (
	"fmt"
	"os"

	"golang.org/x/term"
)

func main() {
	fd := int(os.Stdin.Fd())

	fmt.Print("Password: ")
	password, err := term.ReadPassword(fd)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	fmt.Println()

	if len(password) == 0 {
		fmt.Fprintln(os.Stderr, "empty password")
		os.Exit(1)
	}
	fmt.Println("Password received")
}

Run it in a real terminal with go run main.go (not an IDE run pane without a TTY). Sample interaction:

text
Password:
Password received

Nothing appears as you type at the Password: prompt; after Enter you get a blank line and Password received. Check err before using the returned []byte.


Detect non-terminal input with term.IsTerminal

ReadPassword already attempts terminal-specific handling and returns an error when the descriptor cannot be used appropriately. term.IsTerminal(fd) independently reports whether a file descriptor is a terminal.

If your program needs different behavior for interactive and non-interactive input, check stdin with term.IsTerminal before calling ReadPassword:

go
fd := int(os.Stdin.Fd())
fmt.Println(term.IsTerminal(fd))

When this prints false, stdin is often a pipe, a redirected file, output from another process, or a CI runner without a TTY. ReadPassword is for terminal input; pipes and redirected stdin need a separate input path.

One common pattern is to fail early with a clear message:

go
if !term.IsTerminal(fd) {
	fmt.Fprintln(os.Stderr, "password input requires an interactive terminal")
	os.Exit(1)
}

Add that guard to main.go before the ReadPassword call. Piped stdin then stops before ReadPassword runs:

bash
echo test | go run main.go
output
password input requires an interactive terminal
exit status 1

Does ReadPassword show asterisks?

term.ReadPassword disables echo completely; it does not print *. Asterisk masking requires reading individual keystrokes in raw mode or using a terminal/TUI library. For normal CLI password prompts, no-echo input with ReadPassword is simpler.


Common errors

Problem Cause
inappropriate ioctl for device on Linux/Unix stdin is not an interactive terminal
Password appears on screen Input was read with normal stdin APIs instead of terminal echo control
No ***** appears ReadPassword disables echo; it does not mask with asterisks
Works on terminal but not pipe/CI stdin is not a terminal; use a separate non-interactive input path
Extra blank or missing line after prompt Handle prompt and newline placement explicitly

Summary

Hide password input in Go with term.ReadPassword(int(os.Stdin.Fd())): print a prompt, read without echo, then print a newline before any further output. The function does not draw asterisks while typing.

When stdin may not be a terminal, use term.IsTerminal to branch to a separate non-interactive input path. Do not print or log the returned bytes in examples or debug output.


References


Frequently Asked Questions

1. How do I hide password input in Go?

Use golang.org/x/term ReadPassword on int(os.Stdin.Fd()). It reads one line while local echo is disabled, so characters do not appear as the user types. Print your own prompt and a newline after Enter.

2. Does term.ReadPassword display asterisks?

No. ReadPassword disables echo completely. It does not print one asterisk per keystroke. Masked echo requires raw terminal input handling or a TUI library.

3. Why does ReadPassword return inappropriate ioctl for device?

On Unix-like systems, non-terminal input may produce an error such as inappropriate ioctl for device. The exact error can vary by platform. Piped or redirected stdin is the usual cause.

4. Does golang.org/x/term work on Windows?

Yes. The module implements terminal helpers for Windows and Unix. Still pass int(os.Stdin.Fd()) and handle non-interactive stdin the same way you would on Linux.

5. Can I read a password from a pipe or CI job?

ReadPassword is for terminal input. Pipes and redirected stdin need a separate input path.

6. Is hiding a password the same as hashing it?

No. Hiding input controls what appears on screen while the user types. Hashing controls how a password is stored or verified later. They solve different problems.
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, networking, and security, delivering robust and efficient solutions for diverse projects.

  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security
  • Cloud Computing
  • Kubernetes
  • Linux
  • Ansible (software)