# qor/auth, a modular Go authentication system with pluggable providers

> qor/auth assembles password and OAuth logins for a Go web application behind one router mount, with each provider registered separately and login records kept apart from user records so one account can carry several ways in. It leans on the older qor ecosystem, GORM v1 and a session manager that has to be mounted by hand.

**qor/auth** — Golang Authentication solution

- Repository: https://github.com/qor/auth
- Stars: 777 · Forks: 98
- Language: Go
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/qor-auth

## The three-step shape of getting Auth running

qor/auth is a modular authentication system for web development in Go, providing different authentication backends so a project does not have to build them. The README lists the shipped backends as database password, GitHub, Google, Facebook and Twitter, and it makes the extension point explicit: adding another is a matter of implementing Auth's Provider interface.

The stated flow is three steps. Initialise Auth with a configuration, register some providers, and register Auth into the router. That is the whole mental model, and it is reflected in the code, where each provider is a constructor taking a small config struct.

```go
  Auth.RegisterProvider(password.New(&password.Config{}))

  Auth.RegisterProvider(github.New(&github.Config{
    ClientID:     "github client id",
    ClientSecret: "github client secret",
  }))
```

The instance is created with a Config that takes the database handle:

```go
  Auth = auth.New(&auth.Config{
    DB: gormDB,
  })
```

and it is mounted on a router in one line, with the auth routes living under a prefix:

```go
  mux.Handle("/auth/", Auth.NewServeMux())
```

Once mounted, the README says you can go to the login URL and use the features, listing login, logout, register and forgot or change password. That is a pleasant property for a library: the endpoints exist as soon as you mount it, and the default pages are served even before you design anything.

The one thing that must not be forgotten is the session middleware, which the README returns to twice and which is easy to skim past.

## Why login records and user records are separate

Auth has two models and the README explains the reason for the split, which is the design decision worth understanding before you wire it into your own schema.

The AuthIdentityModel stores login information and the UserModel stores user information. The reason for two tables, as the README puts it, is the ability to link a user to multiple auth info records, so one user can have several ways to log in. A person might register with a password, then sign in with GitHub later, and the application should recognise both as the same account.

Each provider records what it needs, because a password provider uses a username and password while a GitHub provider uses the GitHub user ID, and each saves that information into its own record.

Both models are optional in practice. You are not required to set the AuthIdentityModel, since Auth ships a default definition, though if you replace it the README warns you must embed auth_identity.Basic, because Auth assumes the same data structure in your database so it can query and create records with SQL. There is no default UserModel defined, but the README notes you can still use Auth's features, with Auth returning the used auth info record as the logged user. Once you point UserModel at your own User struct, Auth creates or fetches a user through the UserStorer and links its ID to the auth identity record.

If you do not need multiple login methods per account, the README says you can set both models to the same one or skip UserModel entirely.

## Views, mail and the redirector

Rendering is delegated to the qor render package, and the README points there for registering function maps and extending view paths. The view paths can be prepended through the ViewPaths configuration, which is the documented way to replace the default pages. The README is blunt about the defaults, calling them ugly, and points to the auth_themes repository as the place to look for a better set of pages.

If you want to compile the application into a single binary, the README refers to the BindataFS package for embedding assets.

Email is handled by the qor mailer package, and there is a warning that matters in production: by default Auth prints emails to the console rather than sending them. That default is fine for development, and wrong for a deployment where password reset has to reach a real inbox.

After certain actions, such as logging in, registering or confirming, Auth redirects the user. The Redirector configuration chooses the destination, and the default is the home page. If you want a return to the page the user came from, the README recommends the redirect_back package, configured with the session manager and a list of ignored prefixes:

```go
var RedirectBack = redirect_back.New(&redirect_back.Config{
	SessionManager:  manager.SessionManager,
	IgnoredPrefixes: []string{"/auth"},
})
```

There is a catch the README spells out: redirect_back needs to save the last visited URL into the session on each request, so it has to be mounted along with the session manager middleware, in that order.

```go
http.ListenAndServe(":9000", manager.SessionManager.Middleware(RedirectBack.Middleware(mux)))
```

## Sessions, storage interfaces and the dependency vintage

Sessions and flash messages are handled by a Session Storer, which the README says can be replaced by implementing the Session Storer interface. The default implementation uses the qor session package's default manager to save data into cookies, and the same section explains the User Storer, which by default creates and fetches the user based on the AuthIdentityModel and UserModel definitions and can also be replaced with your own implementation of the User Storer interface.

The cookie-based session approach is what makes the session middleware mandatory rather than optional. If you mount the auth mux but forget the middleware, login state has nowhere to live. The README shows the pattern repeatedly:

```go
func main() {
	mux := http.NewServeMux()

	// Register Router
	mux.Handle("/auth/", Auth.NewServeMux())
	http.ListenAndServe(":9000", manager.SessionManager.Middleware(mux))
}
```

Now the dependency picture, which is the part to weigh before adopting. The go.mod file declares go 1.26.0 and requires the older generation of gorm at github.com/jinzhu/gorm v1.9.16, plus a set of sibling qor packages including session, render, mailer, responder, roles, redirect_back, middlewares and qor itself. OAuth work is done through golang.org/x/oauth2 and github.com/mrjones/oauth, and github.com/google/go-github handles the GitHub API. The password hashing comes from golang.org/x/crypto, and jwt/v4 is present for token handling.

Several of these are pinned to old pseudo-versions, which is the practical signal. There are no GitHub releases for the project, so there is no version ladder to consult, and a project whose sibling packages date from the late 2010s will need checking against current Go and database tooling before it goes into production.

## Where qor/auth sits against modern Go authentication

The obvious alternative is a maintained OAuth2 library combined with your own login endpoints, which is what many Go teams do now with golang.org/x/oauth2 directly plus a small handler for the callback and a session layer of their choosing. The difference in approach is that qor/auth ships the whole flow as a mounted mux: login, logout, register, password reset and confirmation all arrive as routes with default pages, and providers are added by registering them rather than by writing handlers.

That is a real saving for an application that wants exactly this set of features. It is also a constraint. The providers are fixed at compile time in the sense that the credentials live in your binary, there is no database-backed client configuration, and the README documents no concept of scopes or per-provider permissions beyond the AllowedDomains option the Google provider exposes. The Google config in the README shows that option with the comment that an empty slice accepts all domains and a whitelist restricts it, which is a domain-level control rather than a scope model.

The other alternative is to delegate authentication to an identity provider such as Auth0, Clerk or an internal OIDC server. The difference there is that identity lives outside your database, the session handling is theirs, and your application becomes a relying party. qor/auth keeps the credentials and the user records in your own database through GORM, which is what you want when you need full control of the user model and what you do not want when you need multi-factor authentication, password policy enforcement or account recovery handled for you.

The honest summary is that qor/auth is a coherent, older but complete package for a specific stack. It fits an application already built on qor, GORM v1 and server rendered pages. It does not fit a greenfield service that wants managed identity.

## Conclusion

Adopt qor/auth if your Go application already uses the qor ecosystem and wants password plus OAuth login wired in a few dozen lines rather than a full identity provider. Skip it if you are starting a new service, because the dependency set is old, it uses GORM v1, and it has no GitHub releases to pin versions against. Verify first by registering only the password provider, confirming the default views render at /auth/login on your router, and checking that your session manager middleware is mounted before you rely on login state.

## FAQ

### Which authentication providers does qor/auth ship with?

The README lists database password, GitHub, Google, Facebook and Twitter. Additional providers are added by implementing Auth's Provider interface.

### How do I mount qor/auth into a Go router?

Create the instance with auth.New passing a Config containing the database handle, register the providers you want, then mount it with mux.Handle("/auth/", Auth.NewServeMux()). After that the login, logout, register and password change routes are available under that prefix.

### Why does qor/auth use two models for users and identities?

The split exists so a user can be linked to multiple auth info records and therefore log in in several ways, for example with a password and with GitHub. Each provider records what it needs in its own identity record, and the UserModel holds the application-level user.

### Does qor/auth send password reset emails by default?

No. The README states that Auth uses the Mailer package to send emails but that by default it prints emails to the console, so you need to configure it to send real ones.

### What must I remember when using qor/auth sessions?

The session manager middleware has to be registered on your router, for example http.ListenAndServe(":9000", manager.SessionManager.Middleware(mux)), otherwise login state has nowhere to be stored. If you use redirect_back as the Redirector, mount it inside the session middleware as well.

## Sources

- [Issues](https://github.com/qor/auth/issues)
- [License: MIT](https://github.com/qor/auth/blob/master/LICENSE)
- [qor/auth on GitHub](https://github.com/qor/auth)
- [README](https://github.com/qor/auth/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/qor-auth
