go-password and the AgileBits algorithm moved into Go
A Golang library for generating high-entropy random passwords similar to 1Password or LastPass.
At a glance
- What is it?
- go-password is a small Go library that generates high-entropy random passwords using the same algorithm AgileBits describes for 1Password, with crypto/rand as the entropy source. It is one function with four numbers, and the interesting part is the set of policies you can request, including the no-repeats and allow-repeat switches.
- Who is it for?
- go-password is a good fit for a Go service that needs to mint a password or a token with a controlled character mix, since the algorithm is the one AgileBits documents for 1Password and the entropy comes from crypto/rand rather than a math/rand source.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 98 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
One function, four numbers
The library implements generation of random passwords with provided requirements, as described by AgileBits for 1Password, in pure Golang. The README notes the algorithm is commonly used when generating website passwords, and that the library uses crypto/rand for added randomness.
The entire public surface in the usage example is one call:
package main
import (
"log"
"github.com/sethvargo/go-password/password"
)
func main() {
// Generate a password that is 64 characters long with 10 digits, 10 symbols,
// allowing upper and lower case letters, disallowing repeat characters.
res, err := password.Generate(64, 10, 10, false, false)
if err != nil {
log.Fatal(err)
}
log.Print(res)
}The four arguments are the total character count, the number of digits, the number of symbols, and two booleans that control whether upper and lower case letters are allowed. The comment in the example spells out what the false, false pair means in that particular call, which is worth pausing on, because the two booleans are not "allow upper" and "allow lower".
The point of the library is that it is a specification rather than a personality. You ask for 64 characters, 10 digits, 10 symbols, and a case policy, and you get exactly that mix, as opposed to a password that happens to contain some letters.
The audience is a Go developer who needs a password with a known composition, typically generating a credential for a user or a service account.
What crypto/rand buys and what it does not
The choice of crypto/rand is the substantive engineering decision in a package this small, and the README is direct that it is there for added randomness.
In Go, the standard math/rand generator is deterministic and fast, which is what you want for shuffling, sampling and simulations, and exactly what you do not want for a credential. A math/rand-based password generator with a predictable seed produces a predictable password, and a generator seeded from the clock produces one an attacker can narrow down. crypto/rand reads from the operating system's entropy source, so the output is not reproducible and not reconstructable from a small amount of leaked state.
The second thing the library does is use the AgileBits algorithm rather than inventing its own. That matters more than it might sound. The character selection strategy in a password generator is where subtle mistakes live, particularly around modulo bias, where taking a random byte modulo the size of the alphabet skews the distribution toward the first characters in the alphabet whenever the alphabet size does not divide the byte range. A well-reviewed published algorithm is easier to trust than a fresh implementation of the same idea, and the README is explicit that the algorithm is the one described by AgileBits for 1Password.
The sample outputs in the README illustrate the character repertoire, including a mix of upper case, lower case, digits and punctuation, with a length that varies from six characters to sixty-four depending on the parameters.
The policy caveat the README puts in a blockquote
There is a caveat in the README that deserves more attention than a blockquote usually gets, because it changes how you should use the library.
Since the passwords are completely randomized, it is possible that they may generate passwords that don't comply with some custom password policies, such as ones that require both upper case and lower case letters. If your use case needs a mix of casing, the README gives two options: increase the number of characters in the password, or check the output and regenerate if it fails a particular constraint.
That is the honest behaviour of a generator that samples from a distribution rather than a constraint solver. A generator that guaranteed one of each category would do so by biasing the selection, and that bias is exactly the kind of subtle entropy loss that a library like this is better off without. The README is choosing correctness of distribution over composition guarantees, and telling you about the consequence.
So the integration pattern is: generate, validate against your own policy, retry if it fails. The mock generator exists in the package precisely because of this. Since the passwords are completely randomized, it is possible that they may generate passwords that don't comply with some custom password policies, and the test story in the README is built around a canned response rather than a random one.
The interface exists for testability
The testing section is short and it is the part of the API design worth copying.
For testing purposes, instead of accepting a *password.Generator struct, accept a password.PasswordGenerator interface:
// func MyFunc(p *password.Generator)
func MyFunc(p password.PasswordGenerator) {
// ...
}The comment in the example shows the shape of the change, and it is a small one: the parameter type becomes an interface rather than a concrete struct, and the function body does not change.
Then in the test, use a mocked generator with stubbed data:
func TestMyFunc(t *testing.T) {
gen := password.NewMockGenerator("canned-response", false)
MyFunc(gen)
}And the behaviour is deterministic: the mock generator will always return the value "canned-response", regardless of the provided parameters. The second argument to NewMockGenerator is presumably the same boolean as in the real generator, and it is false in the example.
This is the standard Go answer to a package whose only output is random. Without the interface, any test that touched password generation would either be flaky or would have to assert on a regex for shape rather than on a value. With it, the test asserts on the exact string, and the randomness is confined to the one place it belongs.
Module, build and the state of the repository
The module is github.com/sethvargo/go-password, and the go.mod is three lines long: the module path, a go directive of 1.25, and nothing else. There are no dependencies, which is what you would expect from a package that reads crypto/rand and does arithmetic.
The go 1.25 directive is the one thing to notice. It is a floor, not a preference, and it is higher than the Go version a great many services in production are running. If your build pipeline pins an older toolchain, this module will not build until you raise it.
The Makefile is equally short, with a single test target that runs the Go test runner with count=1 to avoid the test cache, the race detector enabled, shuffle=on to randomise test order, a five minute timeout, vet=all, and the verbose flag. The shuffle flag is a small detail that says something about how the author works, since randomised test order is how you catch tests that depend on each other.
The repository layout is a LICENSE, a Makefile, a README, the go.mod and a password/ directory, which is the whole source. The licence is MIT. The repository is not archived, and the last push was on 2026-07-17, the same day as the v0.4.0 tag, which is the only release listed.
Where this stops being enough
Two limits follow from what the library is.
The first is the composition guarantee discussed above. If your system requires a specific character class to be present, this library will not promise that, and you need a validation loop around it. A generator that does guarantee composition is a different tool with different entropy properties, and choosing between them is a decision about which property matters more, guaranteed structure or unconstrained sampling.
The second is scope. This package generates a string. It does not store it, does not hash it, does not salt it, does not check it against a breach corpus, and does not measure the resulting entropy in bits. The README calls the result a password and describes the algorithm as the one used for website passwords, and that is the whole contract.
For anything that needs a secret at rest, that work is elsewhere. A generated password still has to be stored safely, and a service that mints credentials for users is usually better served by a password hashing library and a reset flow than by generating and holding the credential yourself.
There is also a small integration risk that comes with the version floor. A module requiring go 1.25 cannot be consumed by a project on an earlier toolchain, and a library this widely useful tends to be pulled in transitively, so the constraint can surface in a dependency you did not choose to take on.
Editorial conclusion
go-password is a good fit for a Go service that needs to mint a password or a token with a controlled character mix, since the algorithm is the one AgileBits documents for 1Password and the entropy comes from crypto/rand rather than a math/rand source. It is a poor fit if you need guaranteed composition guarantees, because the library explicitly says a generated password may not satisfy a custom policy such as requiring both upper and lower case, and it is a poor fit for secret storage since it generates and does not manage. Before adopting, call the generator with your real policy parameters and check the output against your own validator, and remember that the module declares go 1.25, so the toolchain floor is higher than most Go services currently run.
Frequently asked questions
How do I generate a password with go-password?
Call password.Generate with the total length, the number of digits, the number of symbols and the two case-policy booleans, for example password.Generate(64, 10, 10, false, false), and handle the returned error. The package is installed with go get github.com/sethvargo/go-password/password.
What randomness source does go-password use?
The library uses crypto/rand for added randomness, and it implements the generation algorithm described by AgileBits for 1Password rather than a custom scheme, in pure Golang with no external dependencies.
How do I test code that generates passwords with go-password?
Accept a password.PasswordGenerator interface rather than a *password.Generator struct, then use password.NewMockGenerator("canned-response", false) in the test. The mock always returns the given value regardless of the provided parameters.
Does go-password guarantee the character mix in the generated password?
No. The README warns that because the passwords are completely randomized they may not comply with custom policies such as requiring both upper and lower case letters, and suggests either increasing the character count or checking the output and regenerating when it fails a constraint.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/sethvargo-go-password)Was this useful?