authboss

package module
v2.4.1+incompatible Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 19, 2020 License: MIT Imports: 16 Imported by: 0

README

Authboss

GoDoc Build Status Coverage Status Mail

Authboss is a modular authentication system for the web.

It has several modules that represent authentication and authorization features that are common to websites in general so that you can enable as many as you need, and leave the others out. It makes it easy to plug in authentication to an application and get a lot of functionality for (hopefully) a smaller amount of integration effort.

New to v2?

v1 -> v2 was a very big change. If you're looking to upgrade there is a general guide in tov2.md in this project.

Why use Authboss?

Every time you'd like to start a new web project, you really want to get to the heart of what you're trying to accomplish very quickly and it would be a sure bet to say one of the systems you're excited about implementing and innovating on is not authentication. In fact it's very much the opposite: it's one of those things that you have to do and one of those things you loathe to do. Authboss is supposed to remove a lot of the tedium that comes with this, as well as a lot of the chances to make mistakes. This allows you to care about what you're intending to do, rather than care about ancillary support systems required to make what you're intending to do happen.

Here are a few bullet point reasons you might like to try it out:

  • Saves you time (Authboss integration time should be less than re-implementation time)
  • Saves you mistakes (at least using Authboss, people can bug fix as a collective and all benefit)
  • Should integrate with or without any web framework

Readme Table of Contents

Getting Started

To get started with Authboss in the simplest way, is to simply create a Config, populate it with the things that are required, and start implementing use cases. The use cases describe what's required to be able to use a particular piece of functionality, or the best practice when implementing a piece of functionality. Please note the app requirements for your application as well integration requirements that follow.

Of course the standard practice of fetching the library is just the beginning:

# Get the latest, keep in mind you should be vendoring with dep or using vgo at this point
# To ensure versions don't get messed up underneath you
go get -u github.com/volatiletech/authboss

Here's a bit of starter code that was stolen from the sample.

ab := authboss.New()

ab.Config.Storage.Server = myDatabaseImplementation
ab.Config.Storage.SessionState = mySessionImplementation
ab.Config.Storage.CookieState = myCookieImplementation

ab.Config.Paths.Mount = "/authboss"
ab.Config.Paths.RootURL = "https://www.example.com/"

// This is using the renderer from: github.com/volatiletech/authboss
ab.Config.Core.ViewRenderer = abrenderer.New("/auth")
// Probably want a MailRenderer here too.

// Set up defaults for basically everything besides the ViewRenderer/MailRenderer in the HTTP stack
defaults.SetCore(&ab.Config, false)

if err := ab.Init(); err != nil {
    panic(err)
}

// Mount the router to a path (this should be the same as the Mount path above)
// mux in this example is a chi router, but it could be anything that can route to
// the Core.Router.
mux.Mount("/authboss", http.StripPrefix("/authboss", ab.Config.Core.Router))

For a more in-depth look you definitely should look at the authboss sample to see what a full implementation looks like. This will probably help you more than any of this documentation.

https://github.com/volatiletech/authboss-sample

App Requirements

Authboss does a lot of things, but it doesn't do some of the important things that are required by a typical authentication system, because it can't guarantee that you're doing many of those things in a different way already, so it punts the responsibility.

CSRF Protection

What this means is you should apply a middleware that can protect the application from crsf attacks or you may be vulnerable. Authboss previously handled this but it took on a dependency that was unnecessary and it complicated the code. Because Authboss does not render views nor consumes data directly from the user, it no longer does this.

Request Throttling

Currently Authboss is vulnerable to brute force attacks because there are no protections on it's endpoints. This again is left up to the creator of the website to protect the whole website at once (as well as Authboss) from these sorts of attacks.

Integration Requirements

In terms of integrating Authboss into your app, the following things must be considered.

Middleware

There are middlewares that are required to be installed in your middleware stack if it's all to function properly, please see Middlewares for more information.

Configuration

There are some required configuration variables that have no sane defaults and are particular to your app:

  • Config.Paths.Mount
  • Config.Paths.RootURL
Storage and Core implementations

Everything under Config.Storage and Config.Core are required and you must provide them, however you can optionally use default implementations from the defaults package. This also provides an easy way to share implementations of certain stack pieces (like HTML Form Parsing). As you saw in the example above these can be easily initialized with the SetCore method in that package.

The following is a list of storage interfaces, they must be provided by the implementer. Server is a very involved implementation, please see the additional documentation below for more details.

  • Config.Storage.Server
  • Config.Storage.SessionState
  • Config.Storage.CookieState (only for "remember me" functionality)

The following is a list of the core pieces, these typically are abstracting the HTTP stack. Out of all of these you'll probably be mostly okay with the default implementations in the defaults package but there are two big exceptions to this rule and that's the ViewRenderer and the MailRenderer. For more information please see the use case Rendering Views

  • Config.Core.Router
  • Config.Core.ErrorHandler
  • Config.Core.Responder
  • Config.Core.Redirector
  • Config.Core.BodyReader
  • Config.Core.ViewRenderer
  • Config.Core.MailRenderer
  • Config.Core.Mailer
  • Config.Core.Logger
ServerStorer implementation

The ServerStorer is meant to be upgraded to add capabilities depending on what modules you'd like to use. It starts out by only knowing how to save and load users, but the remember module as an example needs to be able to find users by remember me tokens, so it upgrades to a RememberingServerStorer which adds these abilities.

Your ServerStorer implementation does not need to implement all these additional interfaces unless you're using a module that requires it. See the Use Cases documentation to know what the requirements are.

User implementation

Users in Authboss are represented by the User interface. The user interface is a flexible notion, because it can be upgraded to suit the needs of the various modules.

Initially the User must only be able to Get/Set a PID or primary identifier. This allows the authboss modules to know how to refer to him in the database. The ServerStorer also makes use of this to save/load users.

As mentioned, it can be upgraded, for example suppose now we want to use the confirm module, in that case the e-mail address now becomes a requirement. So the confirm module will attempt to upgrade the user (and panic if it fails) to a ConfirmableUser which supports retrieving and setting of confirm tokens, e-mail addresses, and a confirmed state.

Your User implementation does not need to implement all these additional user interfaces unless you're using a module that requires it. See the Use Cases documentation to know what the requirements are.

Values implementation

The BodyReader interface in the Config returns Validator implementations which can be validated. But much like the storer and user it can be upgraded to add different capabilities.

A typical BodyReader (like the one in the defaults package) implementation checks the page being requested and switches on that to parse the body in whatever way (msgpack, json, url-encoded, doesn't matter), and produce a struct that has the ability to Validate() it's data as well as functions to retrieve the data necessary for the particular valuer required by the module.

An example of an upgraded Valuer is the UserValuer which stores and validates the PID and Password that a user has provided for the modules to use.

Your body reader implementation does not need to implement all valuer types unless you're using a module that requires it. See the Use Cases documentation to know what the requirements are.

Config

The config struct is an important part of Authboss. It's the key to making Authboss do what you want with the implementations you want. Please look at it's code definition as you read the documentation below, it will make much more sense.

Config Struct Documentation

Paths

Paths are the paths that should be redirected to or used in whatever circumstance they describe. Two special paths that are required are Mount and RootURL without which certain authboss modules will not function correctly. Most paths get defaulted to / such as after login success or when a user is locked out of their account.

Modules

Modules are module specific configuration options. They mostly control the behavior of modules. For example RegisterPreserveFields decides a whitelist of fields to allow back into the data to be re-rendered so the user doesn't have to type them in again.

Mail

Mail sending related options.

Storage

These are the implementations of how storage on the server and the client are done in your app. There are no default implementations for these at this time. See the Godoc for more information about what these are.

Core

These are the implementations of the HTTP stack for your app. How do responses render? How are they redirected? How are errors handled?

For most of these there are default implementations from the defaults package available, but not for all. See the package documentation for more information about what's available.

Available Modules

Each module can be turned on simply by importing it and the side-effects take care of the rest. Not all the capabilities of authboss are represented by a module, see Use Cases to view the supported use cases as well as how to use them in your app.

Note: The two factor packages do not enable via side-effect import, see their documentation for more information.

Name Import Path Description
Auth github.com/volatiletech/authboss/auth Database password authentication for users.
Confirm github.com/volatiletech/authboss/confirm Prevents login before e-mail verification.
Expire github.com/volatiletech/authboss/expire Expires a user's login
Lock github.com/volatiletech/authboss/lock Locks user accounts after authentication failures.
Logout github.com/volatiletech/authboss/logout Destroys user sessions for auth/oauth2.
OAuth2 github.com/volatiletech/authboss/oauth2 Provides oauth2 authentication for users.
Recover github.com/volatiletech/authboss/recover Allows for password resets via e-mail.
Register github.com/volatiletech/authboss/register User-initiated account creation.
Remember github.com/volatiletech/authboss/remember Persisting login sessions past session cookie expiry.
OTP github.com/volatiletech/authboss/otp One time passwords for use instead of passwords.
Twofactor github.com/volatiletech/authboss/otp/twofactor Regenerate recovery codes for 2fa.
Totp2fa github.com/volatiletech/authboss/otp/twofactor/totp2fa Use Google authenticator-like things for a second auth factor.
Sms2fa github.com/volatiletech/authboss/otp/twofactor/sms2fa Use a phone for a second auth factor.

Middlewares

The only middleware that's truly required is the LoadClientStateMiddleware, and that's because it enables session and cookie handling for Authboss. Without that, it's not a very useful piece of software.

The remaining middlewares are either the implementation of an entire module (like expire), or a key part of a module. For example you probably wouldn't want to use the lock module without the middleware that would stop a locked user from using an authenticated resource, because then locking wouldn't be useful unless of course you had your own way of dealing with locking, which is why it's only recommended, and not required. Typically you will use the middlewares if you use the module.

Name Requirement Description
Middleware Recommended Prevents unauthenticated users from accessing routes.
LoadClientStateMiddleware Required Enables cookie and session handling
ModuleListMiddleware Optional Inserts a loaded module list into the view data
confirm.Middleware Recommended with confirm Ensures users are confirmed or rejects request
expire.Middleware Required with expire Expires user sessions after an inactive period
lock.Middleware Recommended with lock Rejects requests from locked users
remember.Middleware Recommended with remember Logs a user in from a remember cookie

Use Cases

Get Current User

CurrentUser can be retrieved by calling Authboss.CurrentUser but a pre-requisite is that Authboss.LoadClientState has been called first to load the client state into the request context. This is typically achieved by using the Authboss.LoadClientStateMiddleware, but can be done manually as well.

Reset Password

Updating a user's password is non-trivial for several reasons:

  1. The bcrypt algorithm must have the correct cost, and also be being used.
  2. The user's remember me tokens should all be deleted so that previously authenticated sessions are invalid
  3. Optionally the user should be logged out (not taken care of by UpdatePassword)

In order to do this, we can use the Authboss.UpdatePassword method. This ensures the above facets are taken care of which the exception of the logging out part.

If it's also desirable to have the user logged out, please use the following methods to erase all known sessions and cookies from the user.

Note: DelKnownSession has been deprecated for security reasons

User Auth via Password

Info and Requirements
Module auth
Pages login
Routes /login
Emails None
Middlewares LoadClientStateMiddleware
ClientStorage Session and Cookie
ServerStorer ServerStorer
User AuthableUser
Values UserValuer
Mailer None

To enable this side-effect import the auth module, and ensure that the requirements above are met. It's very likely that you'd also want to enable the logout module in addition to this.

Direct a user to GET /login to have them enter their credentials and log in.

User Auth via OAuth2

Info and Requirements
Module oauth2
Pages None
Routes /oauth2/{provider}, /oauth2/callback/{provider}
Emails None
Middlewares LoadClientStateMiddleware
ClientStorage Session
ServerStorer OAuth2ServerStorer
User OAuth2User
Values None
Mailer None

This is a tougher implementation than most modules because there's a lot going on. In addition to the requirements stated above, you must also configure the OAuth2Providers in the config struct.

The providers require an oauth2 configuration that's typical for the Go oauth2 package, but in addition to that they need a FindUserDetails method which has to take the token that's retrieved from the oauth2 provider, and call an endpoint that retrieves details about the user (at LEAST user's uid). These parameters are returned in map[string]string form and passed into the OAuth2ServerStorer.

Please see the following documentation for more details:

User Registration

Info and Requirements
Module register
Pages register
Routes /register
Emails None
Middlewares LoadClientStateMiddleware
ClientStorage Session
ServerStorer CreatingServerStorer
User AuthableUser, optionally ArbitraryUser
Values UserValuer, optionally also ArbitraryValuer
Mailer None

Users can self-register for a service using this module. You may optionally want them to confirm themselves, which can be done using the confirm module.

The complicated part in implementing registrations are around the RegisterPreserveFields. This is to help in the case where a user fills out many fields, and then say enters a password which doesn't meet minimum requirements and it fails during validation. These preserve fields should stop the user from having to type in all that data again (it's a whitelist). This must be used in conjuction with ArbitraryValuer and although it's not a hard requirement ArbitraryUser should be used otherwise the arbitrary values cannot be stored in the database.

When the register module sees arbitrary data from an ArbitraryValuer, it sets the data key authboss.DataPreserve with a map[string]string in the data for when registration fails. This means the (whitelisted) values entered by the user previously will be accessible in the templates by using .preserve.field_name. Preserve may be empty or nil so use {{with ...}} to make sure you don't have template errors.

There is additional Godoc documentation on the RegisterPreserveFields config option as well as the ArbitraryUser and ArbitraryValuer interfaces themselves.

Confirming Registrations

Info and Requirements
Module confirm
Pages confirm
Routes /confirm
Emails confirm_html, confirm_txt
Middlewares LoadClientStateMiddleware, confirm.Middleware
ClientStorage Session
ServerStorer ConfirmingServerStorer
User ConfirmableUser
Values ConfirmValuer
Mailer Required

Confirming registrations via e-mail can be done with this module (whether or not done via the register module).

A hook on register kicks off the start of a confirmation which sends an e-mail with a token for the user. When the user re-visits the page, the BodyReader must read the token and return a type that returns the token.

Confirmations carry two values in the database to prevent a timing attack. The selector and the verifier, always make sure in the ConfirmingServerStorer you're searching by the selector and not the verifier.

Password Recovery

Info and Requirements
Module recover
Pages recover_start, recover_middle (not used for renders, only values), recover_end
Routes /recover, /recover/end
Emails recover_html, recover_txt
Middlewares LoadClientStateMiddleware
ClientStorage Session
ServerStorer RecoveringServerStorer
User RecoverableUser
Values RecoverStartValuer, RecoverMiddleValuer, RecoverEndValuer
Mailer Required

The flow for password recovery is that the user is initially shown a page that wants their PID to be entered. The RecoverStartValuer retrieves that on POST to /recover.

An e-mail is sent out, and the user clicks the link inside it and is taken back to /recover/end as a GET, at this point the RecoverMiddleValuer grabs the token and will insert it into the data to be rendered.

They enter their password into the form, and POST to /recover/end which sends the token and the new password which is retrieved by RecoverEndValuer which sets their password and saves them.

Password recovery has two values in the database to prevent a timing attack. The selector and the verifier, always make sure in the RecoveringServerStorer you're searching by the selector and not the verifier.

Remember Me

Info and Requirements
Module remember
Pages None
Routes None
Emails None
Middlewares LoadClientStateMiddleware,
Middlewares LoadClientStateMiddleware, remember.Middleware
ClientStorage Session, Cookies
ServerStorer RememberingServerStorer
User User
Values RememberValuer (not a Validator)
Mailer None

Remember uses cookie storage to log in users without a session via the remember.Middleware. Because of this this middleware should be used high up in the stack, but it also needs to be after the LoadClientStateMiddleware so that client state is available via the authboss mechanisms.

There is an intricacy to the RememberingServerStorer, it doesn't use the User struct at all, instead it simply instructs the storer to save tokens to a pid and recall them just the same. Typically in most databases this will require a separate table, though you could implement using pg arrays or something as well.

A user who is logged in via Remember tokens is also considered "half-authed" which is a session key (authboss.SessionHalfAuthKey) that you can query to check to see if a user should have full rights to more sensitive data, if they are half-authed and they want to change their user details for example you may want to force them to go to the login screen and put in their password to get a full auth first. The authboss.Middleware has a boolean flag to forceFullAuth which prevents half-authed users from using that route.

Locking Users

Info and Requirements
Module lock
Pages None
Routes None
Emails None
Middlewares LoadClientStateMiddleware, lock.Middleware
ClientStorage Session
ServerStorer ServerStorer
User LockableUser
Values None
Mailer None

Lock ensures that a user's account becomes locked if authentication (both auth, oauth2, otp) are failed enough times.

The middleware protects resources from locked users, without it, there is no point to this module. You should put in front of any resource that requires a login to function.

Expiring User Sessions

Info and Requirements
Module expire
Pages None
Routes None
Emails None
Middlewares LoadClientStateMiddleware, expire.Middleware
ClientStorage Session
ServerStorer None
User User
Values None
Mailer None

Note: Unlike most modules in Authboss you must call expire.Setup() to enable this module. See the sample to see how to do this. This may be changed in the future.

Expire simply uses sessions to track when the last action of a user is, if that action is longer than configured then the session is deleted and the user removed from the request context.

This middleware should be inserted at a high level (closer to the request) in the middleware chain to ensure that "activity" is logged properly, as well as any middlewares down the chain do not attempt to do anything with the user before it's removed from the request context.

One Time Passwords

Info and Requirements
Module otp
Pages otp, otpadd, otpclear
Routes /otp/login, /otp/add, /otp/clear
Emails None
Middlewares LoadClientStateMiddleware
ClientStorage Session and Cookie
ServerStorer ServerStorer
User otp.User
Values UserValuer
Mailer None

One time passwords can be useful if users require a backup password in case they lose theirs, or they're logging in on an untrusted computer. This module allows users to add one time passwords, clear them, or log in with them.

Logging in with a one time password instead of a password is identical to having logged in normally with their typical password with the exception that the one time passwords are consumed immediately upon use and cannot be used again.

otp should not be confused with two factor authentication. Although 2fa also uses one-time passwords the otp module has nothing to do with it and is strictly a mechanism for logging in with an alternative to a user's regular password.

Two Factor Authentication

2FA in Authboss is implemented in a few separate modules: twofactor, totp2fa and sms2fa.

You should use two factor authentication in your application if you want additional security beyond that of just simple passwords. Each 2fa module supports a different mechanism for verifying a second factor of authentication from a user.

Two-Factor Recovery
Info and Requirements
Module twofactor
Pages recovery2fa
Routes /2fa/recovery/regen
Emails None
Middlewares LoadClientStateMiddleware
ClientStorage Session
ServerStorer ServerStorer
User twofactor.User
Values None
Mailer None

Note: Unlike most modules in Authboss you must construct a twofactor.Recovery and call .Setup() on it to enable this module. See the sample to see how to do this. This may be changed in the future.

Package twofactor is all about the common functionality of providing backup codes for two factor mechanisms. Instead of each module implementing backup codes on it's own, common functionality has been put here including a route to regenerate backup codes.

Backup codes are useful in case people lose access to their second factor for authentication. This happens when users lose their phones for example. When this occurs, they can use one of their backup-codes.

Backup codes are one-time use, they are bcrypted for security, and they only allow bypassing the 2fa authentication part, they cannot be used in lieu of a user's password, for that sort of recovery see the otp module.

Two-Factor Setup E-mail Authorization
Info and Requirements
Module twofactor
Pages twofactor_verify
Routes /2fa/recovery/regen
Emails twofactor_verify_email_html, twofactor_verify_email_txt
Middlewares LoadClientStateMiddleware
ClientStorage Session
ServerStorer ServerStorer
User twofactor.User
Values twofactor.EmailVerifyTokenValuer
Mailer Required

To enable this feature simply turn on authboss.Config.Modules.TwoFactorEmailAuthRequired and new routes and middlewares will be installed when you set up one of the 2fa modules.

When enabled, the routes for setting up 2fa on an account are protected by a middleware that will redirect to /2fa/{totp,sms}/email/verify where Page twofactor_verify is displayed. The user is prompted to authorize the addition of 2fa to their account. The data for this page contains email and a url for the POST. The url is required because this page is shared between all 2fa types.

Once they POST to the url, a token is stored in their session and an e-mail is sent with that token. When they click the link that goes to /2fa/{totp,sms}/email/verify/end with a token in the query string the session token is verified and exchanged for a value that says they're verified and lastly it redirects them to the setup URL for the type of 2fa they were attempting to setup.

Time-Based One Time Passwords 2FA (totp)
Info and Requirements
Module totp2fa
Pages totp2fa_{setup,confirm,remove,validate}, totp2fa_{confirm,remove}_success
Routes /2fa/totp/{setup,confirm,qr,remove,validate}
Emails None
Middlewares LoadClientStateMiddleware
ClientStorage Session (SECURE!)
ServerStorer ServerStorer
User totp2fa.User
Values TOTPCodeValuer
Mailer None

Note: Unlike most modules in Authboss you must construct a totp2fa.TOTP and call .Setup() on it to enable this module. See the sample to see how to do this This may be changed in the future.

Note: To allow users to regenerate their backup codes, you must also use the twofactor module.

Note: Routes are protected by authboss.Middleware so only logged in users can access them. You can configure whether unauthenticated users should be redirected to log in or are 404'd using the authboss.Config.Modules.RoutesRedirectOnUnathed configuration flag.

Adding 2fa to a user

When a logged in user would like to add 2fa to their account direct them GET /2fa/totp/setup, the GET on this page does virtually nothing so you don't have to use it, just POST immediately to have a smoother flow for the user. This puts the 2fa secret in their session temporarily meaning you must have proper secure sessions for this to be secure.

They will be redirected to GET /2fa/totp/confirm where the data will show totp2fa.DataTOTPSecret, this is the key that user's should enter into their Google Authenticator or similar app. Once they've added it they need to send a POST /2fa/totp/confirm with a correct code which removes the 2fa secret from their session and permanently adds it to their totp2fa.User and 2fa is now enabled for them. The data from the POST will contain a key twofactor.DataRecoveryCodes that contains an array of recovery codes for the user.

If you wish to show the user a QR code, GET /2fa/totp/qr at any time during or after totp2fa setup will return a 200x200 png QR code that they can scan.

Removing 2fa from a user

A user begins by going to GET /2fa/totp/remove and enters a code which posts to POST /2fa/totp/remove and if it's correct they're shown a success page and 2fa is removed from them, if not they get validation errors.

Logging in with 2fa

When a user goes to log in, the totp module checks the user after they log in for the presence of a totp2fa secret, if there is one it does not give them a logged in session value immediately and redirects them to GET /2fa/totp/validate where they must enter a correct code to POST /2fa/totp/validate if the code is correct they're logged in normally as well as they get the session value authboss.Session2FA set to "totp" to prove that they've authenticated with two factors.

Using Recovery Codes

Both when logging in and removing totp2fa from an account, a recovery code may be used instead. They can POST to the same url, they simply send a different form field. The recovery code is consumed on use and may not be used again.

Text Message 2FA (sms)

Package sms2fa uses sms shared secrets as a means to authenticate a user with a second factor: their phone number.

Info and Requirements
Module sms2fa
Pages sms2fa_{setup,confirm,remove,validate}, sms2fa_{confirm,remove}_success
Routes /2fa/{setup,confirm,remove,validate}
Emails None
Middlewares LoadClientStateMiddleware
ClientStorage Session (SECURE!)
ServerStorer ServerStorer
User sms2fa.User, sms2fa.SMSNumberProvider
Values SMSValuer, SMSPhoneNumberValuer
Mailer None

Note: Unlike most modules in Authboss you must construct a sms2fa.SMS and call .Setup() on it to enable this module. See the sample to see how to do this. This may be changed in the future.

Note: To allow users to regenerate their backup codes, you must also use the twofactor module.

Note: Routes are protected by authboss.Middleware so only logged in users can access them. You can configure whether unauthenticated users should be redirected to log in or are 404'd using the authboss.Config.Modules.RoutesRedirectOnUnathed configuration flag.

Note: sms2fa always stores the code it's expecting in the user's session therefore you must have secure sessions or the code itself is not secure!

Note: sms2fa pages all send codes via sms on POST when no data code is given. This is also how users can resend the code in case they did not get it (for example a second POST /2fa/sms/{confirm,remove} with no form-fields filled in will end up resending the code).

Note: Sending sms codes is rate-limited to 1 sms/10 sec for that user, this is controlled by placing a timestamp in their session to prevent abuse.

Adding 2fa to a user

When a logged in user would like to add 2fa to their account direct them GET /2fa/sms/setup where they must enter a phone number. If the logged in user also implements sms2fa.SMSNumberProvider then this interface will be used to retrieve a phone number (if it exists) from the user and put it in sms2fa.DataSMSPhoneNumber so that the user interface can populate it for the user, making it convenient to re-use an already saved phone number inside the user.

Once they POST /2fa/sms/setup with a phone number, the sms2fa.Sender interface will be invoked to send the SMS code to the user and they will be redirected to GET /2fa/sms/confirm where they enter the code they received which does a POST /2fa/sms/confirm to store the phone number they were confirming permanently on their user using sms2fa.User which enables sms2fa for them. The data from the POST will contain a key twofactor.DataRecoveryCodes that contains an array of recovery codes for the user.

Removing 2fa from a user

A user begins by going to GET /2fa/sms/remove. This page does nothing on it's own. In order to begin the process POST /2fa/sms/remove with no data (or a recovery code to skip needing the sms code) to send the sms code to the user. Then they can POST /2fa/sms/remove again with the correct code to have it permanently removed.

Logging in with 2fa

When a user goes to log in, the sms module checks the user after they log in for the presence of a sms2fa phone number, if there is one it does not give them a logged in session value but instead sends an SMS code to their configured number and and redirects them to GET /2fa/sms/validate where they must enter a correct code to POST /2fa/totp/validate. If the code is correct they're logged in normally as well as they get the session value authboss.Session2FA set to "sms" to prove that they've authenticated with two factors.

Using Recovery Codes

Same as totp2fa above.

Rendering Views

The authboss rendering system is simple. It's defined by one interface: Renderer

The renderer knows how to load templates, and how to render them with some data and that's it. So let's examine the most common view types that you might want to use.

HTML Views

When your app is a traditional web application and is generating it's HTML serverside using templates this becomes a small wrapper on top of your rendering setup. For example if you're using html/template then you could just use template.New() inside the Load() method and store that somewhere and call template.Execute() in the Render() method.

There is also a very basic renderer: Authboss Renderer which has some very ugly built in views and the ability to override them with your own if you don't want to integrate your own rendering system into that interface.

JSON Views

If you're building an API that's mostly backed by a javascript front-end, then you'll probably want to use a renderer that converts the data to JSON. There is a simple json renderer available in the defaults package package if you wish to use that.

Data

The most important part about this interface is the data that you have to render. There are several keys that are used throughout authboss that you'll want to render in your views.

They're in the file html_data.go and are constants prefixed with Data. See the documentation in that file for more information on which keys exist and what they contain.

The default responder also happens to collect data from the Request context, and hence this is a great place to inject data you'd like to render (for example data for your html layout, or csrf tokens).

Documentation

Overview

Package authboss is a modular authentication system for the web. It tries to remove as much boilerplate and "hard things" as possible so that each time you start a new web project in Go, you can plug it in, configure and be off to the races without having to think about how to store passwords or remember tokens.

Index

Constants

View Source
const (
	// SessionKey is the primarily used key by authboss.
	SessionKey = "uid"
	// SessionHalfAuthKey is used for sessions that have been authenticated by
	// the remember module. This serves as a way to force full authentication
	// by denying half-authed users acccess to sensitive areas.
	SessionHalfAuthKey = "halfauth"
	// SessionLastAction is the session key to retrieve the
	// last action of a user.
	SessionLastAction = "last_action"
	// Session2FA is set when a user has been authenticated with a second factor
	Session2FA = "twofactor"
	// Session2FAAuthToken is a random token set in the session to be verified
	// by e-mail.
	Session2FAAuthToken = "twofactor_auth_token"
	// Session2FAAuthed is in the session (and set to "true") when the user
	// has successfully verified the token sent via e-mail in the two factor
	// e-mail authentication process.
	Session2FAAuthed = "twofactor_authed"
	// SessionOAuth2State is the xsrf protection key for oauth.
	SessionOAuth2State = "oauth2_state"
	// SessionOAuth2Params is the additional settings for oauth
	// like redirection/remember.
	SessionOAuth2Params = "oauth2_params"

	// CookieRemember is used for cookies and form input names.
	CookieRemember = "rm"

	// FlashSuccessKey is used for storing sucess flash messages on the session
	FlashSuccessKey = "flash_success"
	// FlashErrorKey is used for storing sucess flash messages on the session
	FlashErrorKey = "flash_error"
)
View Source
const (
	CTXKeyPID  contextKey = "pid"
	CTXKeyUser contextKey = "user"

	CTXKeySessionState contextKey = "session"
	CTXKeyCookieState  contextKey = "cookie"

	// CTXKeyData is a context key for the accumulating
	// map[string]interface{} (authboss.HTMLData) to pass to the
	// renderer
	CTXKeyData contextKey = "data"

	// CTXKeyValues is to pass the data submitted from API request or form
	// along in the context in case modules need it. The only module that needs
	// user information currently is remember so only auth/oauth2 are currently
	// going to use this.
	CTXKeyValues contextKey = "values"
)

CTX Keys for authboss

View Source
const (
	// DataErr is for one off errors that don't really belong to
	// a particular field. It should be a string.
	DataErr = "error"
	// DataValidation is for validation errors, it should always
	// have been created using the Map() style functions in the
	// validation method so that html/text template users don't
	// struggle in displaying them.
	//
	// It is: map[string][]string, where the key in the map is the field
	// and the []string on the other side is the list of problems
	// with that field.
	//
	// It's also important to note that if the errors that were Map()'d
	// did not implement FieldError or for generic errors
	// the empty string ("") is used as a key in the map for those
	// errors that couldn't be fit to a specific field.
	DataValidation = "errors"
	// DataPreserve preserves fields during large form exercises
	// like user registration so we don't have to re-type safe
	// information like addresses etc.
	//
	// This data looks like map[string]string, and is simply
	// keyed by the field name, and the value is the field value.
	DataPreserve = "preserve"
	// DataModules contains a map[string]bool of which modules are loaded
	// The bool is largely extraneous and can be ignored, if the module is
	// loaded it will be present in the map, if not it will be missing.
	DataModules = "modules"
)

Keys for use in HTMLData that are meaningful

View Source
const (
	// ConfirmPrefix is prepended to names of confirm fields.
	ConfirmPrefix = "confirm_"
)
View Source
const (
	// FormValueRedirect should be honored by HTTPRedirector implementations
	// as the value from the URL that overrides the typical redirect when
	// FollowRedirParam is set to true.
	FormValueRedirect = "redir"
)

Variables

View Source
var (
	// ErrUserFound should be returned from Create (see ConfirmUser)
	// when the primaryID of the record is found.
	ErrUserFound = errors.New("user found")
	// ErrUserNotFound should be returned from Get when the record is not found.
	ErrUserNotFound = errors.New("user not found")
	// ErrTokenNotFound should be returned from UseToken when the
	// record is not found.
	ErrTokenNotFound = errors.New("token not found")
)

Functions

func DelAllSession

func DelAllSession(w http.ResponseWriter, whitelist []string)

DelAllSession deletes all variables in the session except for those on the whitelist.

The whitelist is typically provided directly from the authboss config.

This is the best way to ensure the session is cleaned up after use for a given user. An example is when a user is expired or logged out this method is called.

func DelCookie

func DelCookie(w http.ResponseWriter, key string)

DelCookie deletes a key-value from the session.

func DelKnownCookie

func DelKnownCookie(w http.ResponseWriter)

DelKnownCookie deletes all known cookie variables, which can be used to delete remember me pieces.

func DelKnownSession

func DelKnownSession(w http.ResponseWriter)

DelKnownSession is deprecated. See DelAllSession for an alternative. DelKnownSession deletes all known session variables, effectively logging a user out.

func DelSession

func DelSession(w http.ResponseWriter, key string)

DelSession deletes a key-value from the session.

func ErrorMap

func ErrorMap(e []error) map[string][]string

ErrorMap is a shortcut to change []error into ErrorList and call Map on it since this is a common operation.

func FlashError

func FlashError(w http.ResponseWriter, r *http.Request) string

FlashError returns FlashError from the session and removes it.

func FlashSuccess

func FlashSuccess(w http.ResponseWriter, r *http.Request) string

FlashSuccess returns FlashSuccessKey from the session and removes it.

func GetCookie

func GetCookie(r *http.Request, key string) (string, bool)

GetCookie fetches a value from the session

func GetSession

func GetSession(r *http.Request, key string) (string, bool)

GetSession fetches a value from the session

func IsFullyAuthed

func IsFullyAuthed(r *http.Request) bool

IsFullyAuthed returns false if the user has a SessionHalfAuth in his session.

func IsTwoFactored

func IsTwoFactored(r *http.Request) bool

IsTwoFactored returns false if the user doesn't have a Session2FA in his session.

func MakeOAuth2PID

func MakeOAuth2PID(provider, uid string) string

MakeOAuth2PID is used to create a pid for users that don't have an e-mail address or username in the normal system. This allows all the modules to continue to working as intended without having a true primary id. As well as not having to divide the regular and oauth stuff all down the middle.

func MergeDataInRequest

func MergeDataInRequest(r **http.Request, other HTMLData)

MergeDataInRequest edits the request pointer to point to a new request with a modified context that contains the merged data.

func Middleware

func Middleware(ab *Authboss, redirectToLogin bool, forceFullAuth bool, force2fa bool) func(http.Handler) http.Handler

Middleware is deprecated. See Middleware2.

func Middleware2

func Middleware2(ab *Authboss, requirements MWRequirements, failureResponse MWRespondOnFailure) func(http.Handler) http.Handler

Middleware2 prevents someone from accessing a route that should be only allowed for users who are logged in. It allows the user through if they are logged in (SessionKey is present in the session).

requirements are set by logical or'ing together requirements. eg:

authboss.RequireFullAuth | authboss.Require2FA

failureResponse is how the middleware rejects the users that don't meet the criteria. This should be chosen from the MWRespondOnFailure constants.

func ModuleListMiddleware

func ModuleListMiddleware(ab *Authboss) func(http.Handler) http.Handler

ModuleListMiddleware puts a map in the data that can be used to provide the renderer with information about which pieces of the views to show. The bool is extraneous, as presence in the map is the indication of wether or not the module is loaded. Data looks like: map[modulename] = true

oauth2 providers are also listed here using the syntax: oauth2.google for an example. Be careful since this doesn't actually mean that the oauth2 module has been loaded so you should do a conditional that checks for both.

func MountedMiddleware

func MountedMiddleware(ab *Authboss, mountPathed, redirectToLogin, forceFullAuth, force2fa bool) func(http.Handler) http.Handler

MountedMiddleware is deprecated. See MountedMiddleware2.

func MountedMiddleware2

func MountedMiddleware2(ab *Authboss, mountPathed bool, reqs MWRequirements, failResponse MWRespondOnFailure) func(http.Handler) http.Handler

MountedMiddleware2 hides an option from typical users in "mountPathed". Normal routes should never need this only authboss routes (since they are behind mountPath typically). This method is exported only for use by Authboss modules, normal users should use Middleware instead.

If mountPathed is true, then before redirecting to a URL it will add the mountpath to the front of it.

func ParseOAuth2PID

func ParseOAuth2PID(pid string) (provider, uid string, err error)

ParseOAuth2PID returns the uid and provider for a given OAuth2 pid

func ParseOAuth2PIDP

func ParseOAuth2PIDP(pid string) (provider, uid string)

ParseOAuth2PIDP returns the uid and provider for a given OAuth2 pid

func PutCookie

func PutCookie(w http.ResponseWriter, key, val string)

PutCookie puts a value into the session

func PutSession

func PutSession(w http.ResponseWriter, key, val string)

PutSession puts a value into the session

func RegisterModule

func RegisterModule(name string, m Moduler)

RegisterModule with the core providing all the necessary information to integrate into authboss.

func RegisteredModules

func RegisteredModules() []string

RegisteredModules returns a list of modules that are currently registered.

func VerifyPassword

func VerifyPassword(user AuthableUser, password string) error

VerifyPassword uses authboss mechanisms to check that a password is correct. Returns nil on success otherwise there will be an error. Simply a helper to do the bcrypt comparison.

Types

type ArbitraryUser

type ArbitraryUser interface {
	User

	// GetArbitrary is used only to display the arbitrary data back to the user
	// when the form is reset.
	GetArbitrary() (arbitrary map[string]string)
	// PutArbitrary allows arbitrary fields defined by the authboss library
	// consumer to add fields to the user registration piece.
	PutArbitrary(arbitrary map[string]string)
}

ArbitraryUser allows arbitrary data from the web form through. You should definitely only pull the keys you want from the map, since this is unfiltered input from a web request and is an attack vector.

type ArbitraryValuer

type ArbitraryValuer interface {
	Validator

	GetValues() map[string]string
}

ArbitraryValuer provides the "rest" of the fields that aren't strictly needed for anything in particular, address, secondary e-mail, etc.

There are two important notes about this interface:

1. That this is composed with Validator, as these fields should both be validated and culled of invalid pieces as they will be passed into ArbitraryUser.PutArbitrary()

2. These values will also be culled according to the RegisterPreserveFields whitelist and sent back in the data under the key DataPreserve.

type AuthableUser

type AuthableUser interface {
	User

	GetPassword() (password string)
	PutPassword(password string)
}

AuthableUser is identified by a password

func MustBeAuthable

func MustBeAuthable(u User) AuthableUser

MustBeAuthable forces an upgrade to an AuthableUser or panic.

type Authboss

type Authboss struct {
	Config
	Events *Events
	// contains filtered or unexported fields
}

Authboss contains a configuration and other details for running.

func New

func New() *Authboss

New makes a new instance of authboss with a default configuration.

func (*Authboss) CurrentUser

func (a *Authboss) CurrentUser(r *http.Request) (User, error)

CurrentUser retrieves the current user from the session and the database. Before the user is loaded from the database the context key is checked. If the session doesn't have the user ID ErrUserNotFound will be returned.

func (*Authboss) CurrentUserID

func (a *Authboss) CurrentUserID(r *http.Request) (string, error)

CurrentUserID retrieves the current user from the session. TODO(aarondl): This method never returns an error, one day we'll change the function signature.

func (*Authboss) CurrentUserIDP

func (a *Authboss) CurrentUserIDP(r *http.Request) string

CurrentUserIDP retrieves the current user but panics if it's not available for any reason.

func (*Authboss) CurrentUserP

func (a *Authboss) CurrentUserP(r *http.Request) User

CurrentUserP retrieves the current user but panics if it's not available for any reason.

func (*Authboss) Email

func (a *Authboss) Email(ctx context.Context, email Email, ro EmailResponseOptions) error

Email renders the e-mail templates for the given email and sends it using the mailer.

func (*Authboss) Init

func (a *Authboss) Init(modulesToLoad ...string) error

Init authboss, modules, renderers

func (*Authboss) IsLoaded

func (a *Authboss) IsLoaded(mod string) bool

IsLoaded checks if a specific module is loaded.

func (*Authboss) LoadClientState

func (a *Authboss) LoadClientState(w http.ResponseWriter, r *http.Request) (*http.Request, error)

LoadClientState loads the state from sessions and cookies into the ResponseWriter for later use.

func (*Authboss) LoadClientStateMiddleware

func (a *Authboss) LoadClientStateMiddleware(h http.Handler) http.Handler

LoadClientStateMiddleware wraps all requests with the ClientStateResponseWriter as well as loading the current client state into the context for use.

func (*Authboss) LoadCurrentUser

func (a *Authboss) LoadCurrentUser(r **http.Request) (User, error)

LoadCurrentUser takes a pointer to a pointer to the request in order to change the current method's request pointer itself to the new request that contains the new context that has the user in it. Calls LoadCurrentUserID so the primary id is also put in the context.

func (*Authboss) LoadCurrentUserID

func (a *Authboss) LoadCurrentUserID(r **http.Request) (string, error)

LoadCurrentUserID takes a pointer to a pointer to the request in order to change the current method's request pointer itself to the new request that contains the new context that has the pid in it.

func (*Authboss) LoadCurrentUserIDP

func (a *Authboss) LoadCurrentUserIDP(r **http.Request) string

LoadCurrentUserIDP loads the current user id and panics if it's not found

func (*Authboss) LoadCurrentUserP

func (a *Authboss) LoadCurrentUserP(r **http.Request) User

LoadCurrentUserP does the same as LoadCurrentUser but panics if the current user is not found.

func (*Authboss) LoadedModules

func (a *Authboss) LoadedModules() []string

LoadedModules returns a list of modules that are currently loaded.

func (*Authboss) Logger

func (a *Authboss) Logger(ctx context.Context) FmtLogger

Logger returns an appopriate logger for the context: If context is nil, then it simply returns the configured logger. If context is not nil, then it will attempt to upgrade the configured logger to a ContextLogger, and create a context-specific logger for use.

func (*Authboss) NewResponse

NewResponse wraps the ResponseWriter with a ClientStateResponseWriter

func (*Authboss) RequestLogger

func (a *Authboss) RequestLogger(r *http.Request) FmtLogger

RequestLogger returns a request logger if possible, if not it calls Logger which tries to do a ContextLogger, and if that fails it will finally get a normal logger.

func (*Authboss) UpdatePassword

func (a *Authboss) UpdatePassword(ctx context.Context, user AuthableUser, newPassword string) error

UpdatePassword updates the password field of a user using the same semantics that register/auth do to create and verify passwords. It saves this using the storer.

In addition to that, it also invalidates any remember me tokens, if the storer supports that kind of operation.

If it's also desirable to log the user out, use: authboss.DelKnown(Session|Cookie)

type BodyReader

type BodyReader interface {
	Read(page string, r *http.Request) (Validator, error)
}

BodyReader reads data from the request and returns it in an abstract form. Typically used to decode JSON responses or Url Encoded request bodies.

The first parameter is the page that this request was made on so we can tell what kind of JSON object or form was present as well as create the proper validation mechanisms.

A typical example of this is taking the request and turning it into a JSON struct that knows how to validate itself and return certain fields.

type ClientState

type ClientState interface {
	Get(key string) (string, bool)
}

ClientState represents the client's current state and can answer queries about it.

type ClientStateEvent

type ClientStateEvent struct {
	Kind  ClientStateEventKind
	Key   string
	Value string
}

ClientStateEvent are the different events that can be recorded during a request.

type ClientStateEventKind

type ClientStateEventKind int

ClientStateEventKind is an enum.

const (
	// ClientStateEventPut means you should put the key-value pair into the
	// client state.
	ClientStateEventPut ClientStateEventKind = iota
	// ClientStateEventPut means you should delete the key-value pair from the
	// client state.
	ClientStateEventDel
	// ClientStateEventDelAll means you should delete EVERY key-value pair from
	// the client state - though a whitelist of keys that should not be deleted
	// may be passed through as a comma separated list of keys in
	// the ClientStateEvent.Key field.
	ClientStateEventDelAll
)

ClientStateEvent kinds

type ClientStateReadWriter

type ClientStateReadWriter interface {
	// ReadState should return a map like structure allowing it to look up
	// any values in the current session, or any cookie in the request
	ReadState(*http.Request) (ClientState, error)
	// WriteState can sometimes be called with a nil ClientState in the event
	// that no ClientState was read in from LoadClientState
	WriteState(http.ResponseWriter, ClientState, []ClientStateEvent) error
}

ClientStateReadWriter is used to create a cookie storer from an http request. Keep in mind security considerations for your implementation, Secure, HTTP-Only, etc flags.

There's two major uses for this. To create session storage, and remember me cookies.

type ClientStateResponseWriter

type ClientStateResponseWriter struct {
	http.ResponseWriter
	// contains filtered or unexported fields
}

ClientStateResponseWriter is used to write out the client state at the last moment before the response code is written.

func MustClientStateResponseWriter

func MustClientStateResponseWriter(w http.ResponseWriter) *ClientStateResponseWriter

MustClientStateResponseWriter tries to find a csrw inside the response writer by using the UnderlyingResponseWriter interface.

func (ClientStateResponseWriter) Header

Header retrieves the underlying headers

func (ClientStateResponseWriter) Hijack

Hijack implements the http.Hijacker interface by calling the underlying implementation if available.

func (*ClientStateResponseWriter) UnderlyingResponseWriter

func (c *ClientStateResponseWriter) UnderlyingResponseWriter() http.ResponseWriter

UnderlyingResponseWriter for this instance

func (*ClientStateResponseWriter) Write

func (c *ClientStateResponseWriter) Write(b []byte) (int, error)

Write ensures that the client state is written before any writes to the body occur (before header flush to http client)

func (*ClientStateResponseWriter) WriteHeader

func (c *ClientStateResponseWriter) WriteHeader(code int)

WriteHeader writes the header, but in order to handle errors from the underlying ClientStateReadWriter, it has to panic.

type Config

type Config struct {
	Paths struct {
		// Mount is the path to mount authboss's routes at (eg /auth).
		Mount string

		// NotAuthorized is the default URL to kick users back to when
		// they attempt an action that requires them to be logged in and
		// they're not auth'd
		NotAuthorized string

		// AuthLoginOK is the redirect path after a successful authentication.
		AuthLoginOK string

		// ConfirmOK once a user has confirmed their account
		// this says where they should go
		ConfirmOK string
		// ConfirmNotOK is used by the middleware, when a user is still supposed
		// to confirm their account, this is where they should be redirected to.
		ConfirmNotOK string

		// LockNotOK is a path to go to when the user fails
		LockNotOK string

		// LogoutOK is the redirect path after a log out.
		LogoutOK string

		// OAuth2LoginOK is the redirect path after a successful oauth2 login
		OAuth2LoginOK string
		// OAuth2LoginNotOK is the redirect path after
		// an unsuccessful oauth2 login
		OAuth2LoginNotOK string

		// RecoverOK is the redirect path after a successful recovery of a
		// password.
		RecoverOK string

		// RegisterOK is the redirect path after a successful registration.
		RegisterOK string

		// RootURL is the scheme+host+port of the web application
		// (eg https://www.happiness.com:8080) for url generation.
		// No trailing slash.
		RootURL string

		// TwoFactorEmailAuthNotOK is where a user is redirected when
		// the user attempts to add 2fa to their account without verifying
		// their e-mail OR when they've completed the first step towards
		// verification and need to check their e-mail to proceed.
		TwoFactorEmailAuthNotOK string
	}

	Modules struct {
		// BCryptCost is the cost of the bcrypt password hashing function.
		BCryptCost int

		// ConfirmMethod IS DEPRECATED! See MailRouteMethod instead.
		//
		// ConfirmMethod controls which http method confirm expects.
		// This is because typically this is a GET request since it's a link
		// from an e-mail, but in api-like cases it needs to be able to be a
		// post since there's data that must be sent to it.
		ConfirmMethod string

		// ExpireAfter controls the time an account is idle before being
		// logged out by the ExpireMiddleware.
		ExpireAfter time.Duration

		// LockAfter this many tries.
		LockAfter int
		// LockWindow is the waiting time before the number of attemps are reset.
		LockWindow time.Duration
		// LockDuration is how long an account is locked for.
		LockDuration time.Duration

		// LogoutMethod is the method the logout route should use
		// (default should be DELETE)
		LogoutMethod string

		// MailRouteMethod is used to set the type of request that's used for
		// routes that require a token from an e-mail link's query string.
		// This is things like confirm and two factor e-mail auth.
		//
		// You should probably set this to POST if you are building an API
		// so that the user goes to the frontend with their link & token
		// and the front-end calls the API with the token in a POST JSON body.
		//
		// This configuration setting deprecates ConfirmMethod.
		// If ConfirmMethod is set to the default value (GET) then
		// MailRouteMethod is used. If ConfirmMethod is not the default value
		// then it is used until Authboss v3 when only MailRouteMethod will be
		// used.
		MailRouteMethod string

		// MailNoGoroutine is used to prevent the mailer from being launched
		// in a goroutine by the Authboss modules.
		//
		// This behavior will become the default in Authboss v3 and each
		// Mailer implementation will be required to use goroutines if it sees
		// fit.
		//
		// It's important that this is the case if you are using contexts
		// as the http request context will be cancelled by the Go http server
		// and it may interrupt your use of the context that the Authboss module
		// is passing to you, preventing proper use of it.
		MailNoGoroutine bool

		// RegisterPreserveFields are fields used with registration that are
		// to be rendered when post fails in a normal way
		// (for example validation errors), they will be passed back in the
		// data of the response under the key DataPreserve which
		// will be a map[string]string.
		//
		// All fields that are to be preserved must be able to be returned by
		// the ArbitraryValuer.GetValues()
		//
		// This means in order to have a field named "address" you would need
		// to have that returned by the ArbitraryValuer.GetValues() method and
		// then it would be available to be whitelisted by this
		// configuration variable.
		RegisterPreserveFields []string

		// RecoverTokenDuration controls how long a token sent via
		// email for password recovery is valid for.
		RecoverTokenDuration time.Duration
		// RecoverLoginAfterRecovery says for the recovery module after a
		// user has successfully recovered the password, are they simply
		// logged in, or are they redirected to the login page with an
		// "updated password" message.
		RecoverLoginAfterRecovery bool

		// OAuth2Providers lists all providers that can be used. See
		// OAuthProvider documentation for more details.
		OAuth2Providers map[string]OAuth2Provider

		// TwoFactorEmailAuthRequired forces users to first confirm they have
		// access to their e-mail with the current device by clicking a link
		// and confirming a token stored in the session.
		TwoFactorEmailAuthRequired bool

		// TOTP2FAIssuer is the issuer that appears in the url when scanning
		// a qr code for google authenticator.
		TOTP2FAIssuer string

		// DEPRECATED: See ResponseOnUnauthed
		// RoutesRedirectOnUnauthed controls whether or not a user is redirected
		// or given a 404 when they are unauthenticated and attempting to access
		// a route that's login-protected inside Authboss itself.
		// The otp/twofactor modules all use authboss.Middleware to protect
		// their routes and this is the redirectToLogin parameter in that
		// middleware that they pass through.
		RoutesRedirectOnUnauthed bool

		// ResponseOnUnauthed controls how a user is responded to when
		// attempting to access a route that's login-protected inside Authboss
		// itself. The otp/twofactor modules all use authboss.Middleware2 to
		// protect their routes and this is the failResponse parameter in that
		// middleware that they pass through.
		//
		// This deprecates RoutesRedirectOnUnauthed. If RoutesRedirectOnUnauthed
		// is true, the value of this will be set to RespondRedirect until
		// authboss v3.
		ResponseOnUnauthed MWRespondOnFailure
	}

	Mail struct {
		// RootURL is a full path to an application that is hosting a front-end
		// Typically using a combination of Paths.RootURL and Paths.Mount
		// MailRoot will be assembled if not set.
		// Typically looks like: https://our-front-end.com/authenication
		// No trailing slash.
		RootURL string

		// From is the email address authboss e-mails come from.
		From string
		// FromName is the name authboss e-mails come from.
		FromName string
		// SubjectPrefix is used to add something to the front of the authboss
		// email subjects.
		SubjectPrefix string
	}

	Storage struct {
		// Storer is the interface through which Authboss accesses the web apps
		// database for user operations.
		Server ServerStorer

		// CookieState must be defined to provide an interface capapable of
		// storing cookies for the given response, and reading them from the
		// request.
		CookieState ClientStateReadWriter
		// SessionState must be defined to provide an interface capable of
		// storing session-only values for the given response, and reading them
		// from the request.
		SessionState ClientStateReadWriter

		// SessionStateWhitelistKeys are set to preserve keys in the session
		// when authboss.DelAllSession is called. A correct implementation
		// of ClientStateReadWriter will delete ALL session key-value pairs
		// unless that key is whitelisted here.
		SessionStateWhitelistKeys []string
	}

	Core struct {
		// Router is the entity that controls all routing to authboss routes
		// modules will register their routes with it.
		Router Router

		// ErrorHandler wraps http requests with centralized error handling.
		ErrorHandler ErrorHandler

		// Responder takes a generic response from a controller and prepares
		// the response, uses a renderer to create the body, and replies to the
		// http request.
		Responder HTTPResponder

		// Redirector can redirect a response, similar to Responder but
		// responsible only for redirection.
		Redirector HTTPRedirector

		// BodyReader reads validatable data from the body of a request to
		// be able to get data from the user's client.
		BodyReader BodyReader

		// ViewRenderer loads the templates for the application.
		ViewRenderer Renderer
		// MailRenderer loads the templates for mail. If this is nil, it will
		// fall back to using the Renderer created from the ViewLoader instead.
		MailRenderer Renderer

		// Mailer is the mailer being used to send e-mails out via smtp
		Mailer Mailer

		// Logger implies just a few log levels for use, can optionally
		// also implement the ContextLogger to be able to upgrade to a
		// request specific logger.
		Logger Logger
	}
}

Config holds all the configuration for both authboss and it's modules.

func (*Config) Defaults

func (c *Config) Defaults()

Defaults sets the configuration's default values.

type ConfirmValuer

type ConfirmValuer interface {
	Validator

	GetToken() string
}

ConfirmValuer allows us to pull out the token from the request

func MustHaveConfirmValues

func MustHaveConfirmValues(v Validator) ConfirmValuer

MustHaveConfirmValues upgrades a validatable set of values to ones specific to a user that needs to be confirmed.

type ConfirmableUser

type ConfirmableUser interface {
	User

	GetEmail() (email string)
	GetConfirmed() (confirmed bool)
	GetConfirmSelector() (selector string)
	GetConfirmVerifier() (verifier string)

	PutEmail(email string)
	PutConfirmed(confirmed bool)
	PutConfirmSelector(selector string)
	PutConfirmVerifier(verifier string)
}

ConfirmableUser can be in a state of confirmed or not

func MustBeConfirmable

func MustBeConfirmable(u User) ConfirmableUser

MustBeConfirmable forces an upgrade to a ConfirmableUser or panic.

type ConfirmingServerStorer

type ConfirmingServerStorer interface {
	ServerStorer

	// LoadByConfirmSelector finds a user by his confirm selector field
	// and should return ErrUserNotFound if that user cannot be found.
	LoadByConfirmSelector(ctx context.Context, selector string) (ConfirmableUser, error)
}

ConfirmingServerStorer can find a user by a confirm token

func EnsureCanConfirm

func EnsureCanConfirm(storer ServerStorer) ConfirmingServerStorer

EnsureCanConfirm makes sure the server storer supports confirm-lookup operations

type ContextLogger

type ContextLogger interface {
	FromContext(context.Context) Logger
}

ContextLogger creates a logger from a request context

type CreatingServerStorer

type CreatingServerStorer interface {
	ServerStorer

	// New creates a blank user, it is not yet persisted in the database
	// but is just for storing data
	New(ctx context.Context) User
	// Create the user in storage, it should not overwrite a user
	// and should return ErrUserFound if it currently exists.
	Create(ctx context.Context, user User) error
}

CreatingServerStorer is used for creating new users like when Registration or OAuth2 is being done.

func EnsureCanCreate

func EnsureCanCreate(storer ServerStorer) CreatingServerStorer

EnsureCanCreate makes sure the server storer supports create operations

type Email

type Email struct {
	To, Cc, Bcc                []string
	ToNames, CcNames, BccNames []string
	FromName, From             string
	ReplyToName, ReplyTo       string
	Subject                    string

	TextBody string
	HTMLBody string
}

Email all the things. The ToNames and friends are parallel arrays and must be 0-length or the same length as their counterpart. To omit a name for a user at an index in To simply use an empty string at that index in ToNames.

type EmailResponseOptions

type EmailResponseOptions struct {
	Data         HTMLData
	HTMLTemplate string
	TextTemplate string
}

EmailResponseOptions controls how e-mails are rendered and sent

type ErrorHandler

type ErrorHandler interface {
	Wrap(func(w http.ResponseWriter, r *http.Request) error) http.Handler
}

ErrorHandler allows routing to http.HandlerFunc's that additionally return an error for a higher level error handling mechanism.

type ErrorList

type ErrorList []error

ErrorList is simply a slice of errors with helpers.

func (ErrorList) Error

func (e ErrorList) Error() string

Error satisfies the error interface.

func (ErrorList) Map

func (e ErrorList) Map() map[string][]string

Map groups errors by their field name

type Event

type Event int

Event type is for describing events

const (
	EventRegister Event = iota
	EventAuth
	// EventAuthHijack is used to steal the authentication process after a
	// successful auth but before any session variable has been put in.
	// Most useful for defining an additional step for authentication
	// (like 2fa). It needs to be separate to EventAuth because other modules
	// do checks that would also interrupt event handlers with an authentication
	// failure so there's an ordering problem.
	EventAuthHijack
	EventOAuth2
	EventAuthFail
	EventOAuth2Fail
	EventRecoverStart
	EventRecoverEnd
	EventGetUser
	EventGetUserSession
	EventPasswordReset
	EventLogout
)

Event kinds

func (Event) String

func (i Event) String() string

type EventHandler

type EventHandler func(w http.ResponseWriter, r *http.Request, handled bool) (bool, error)

EventHandler reacts to events that are fired by Authboss controllers. These controllers will normally process a request by themselves, but if there is special consideration for example a successful login, but the user is locked, the lock module's controller may seize control over the request.

Very much a controller level middleware.

type Events

type Events struct {
	// contains filtered or unexported fields
}

Events is a collection of Events that fire before and after certain methods.

func NewEvents

func NewEvents() *Events

NewEvents creates a new set of before and after Events.

func (*Events) After

func (c *Events) After(e Event, f EventHandler)

After event, call f.

func (*Events) Before

func (c *Events) Before(e Event, f EventHandler)

Before event, call f.

func (*Events) FireAfter

func (c *Events) FireAfter(e Event, w http.ResponseWriter, r *http.Request) (bool, error)

FireAfter event to all the Events with a context. The error can safely be ignored as it is logged.

func (*Events) FireBefore

func (c *Events) FireBefore(e Event, w http.ResponseWriter, r *http.Request) (bool, error)

FireBefore executes the handlers that were registered to fire before the event passed in.

If it encounters an error it will stop immediately without calling other handlers.

If a handler handles the request, it will pass this information both to handlers further down the chain (to let them know that w has been used) as well as set w to nil as a precaution.

type FieldError

type FieldError interface {
	error
	Name() string
	Err() error
}

FieldError describes an error on a field Typically .Error() has both Name() and Err() together, hence the reason for separation.

type FmtLogger

type FmtLogger struct {
	Logger
}

FmtLogger adds convenience functions on top of the logging methods for formatting.

func (FmtLogger) Errorf

func (f FmtLogger) Errorf(format string, values ...interface{})

Errorf prints to Error() with fmt.Printf semantics

func (FmtLogger) Infof

func (f FmtLogger) Infof(format string, values ...interface{})

Infof prints to Info() with fmt.Printf semantics

type HTMLData

type HTMLData map[string]interface{}

HTMLData is used to render templates with.

func NewHTMLData

func NewHTMLData(data ...interface{}) HTMLData

NewHTMLData creates HTMLData from key-value pairs. The input is a key-value slice, where odd elements are keys, and the following even element is their value.

func (HTMLData) Merge

func (h HTMLData) Merge(other HTMLData) HTMLData

Merge adds the data from other to h. If there are conflicting keys they are overwritten by other's values.

func (HTMLData) MergeKV

func (h HTMLData) MergeKV(data ...interface{}) HTMLData

MergeKV adds extra key-values to the HTMLData. The input is a key-value slice, where odd elements are keys, and the following even element is their value.

type HTTPRedirector

type HTTPRedirector interface {
	Redirect(w http.ResponseWriter, r *http.Request, ro RedirectOptions) error
}

HTTPRedirector redirects http requests to a different url (must handle both json and html) When an authboss controller wants to redirect a user to a different path, it will use this interface.

type HTTPResponder

type HTTPResponder interface {
	Respond(w http.ResponseWriter, r *http.Request, code int, templateName string, data HTMLData) error
}

HTTPResponder knows how to respond to an HTTP request Must consider: - Flash messages - XSRF handling (template data) - Assembling template data from various sources

Authboss controller methods (like the one called in response to POST /auth/login) will call this method to write a response to the user.

type LockableUser

type LockableUser interface {
	User

	GetAttemptCount() (attempts int)
	GetLastAttempt() (last time.Time)
	GetLocked() (locked time.Time)

	PutAttemptCount(attempts int)
	PutLastAttempt(last time.Time)
	PutLocked(locked time.Time)
}

LockableUser is a user that can be locked

func MustBeLockable

func MustBeLockable(u User) LockableUser

MustBeLockable forces an upgrade to a LockableUser or panic.

type Logger

type Logger interface {
	Info(string)
	Error(string)
}

Logger is the basic logging structure that's required

type MWRequirements

type MWRequirements int

MWRequirements are user requirements for authboss.Middleware in order to access the routes in protects. Requirements is a bit-set integer to be able to easily combine requirements like so:

authboss.RequireFullAuth | authboss.Require2FA
const (
	RequireNone MWRequirements = 0x00
	// RequireFullAuth means half-authed users will also be rejected
	RequireFullAuth MWRequirements = 0x01
	// Require2FA means that users who have not authed with 2fa will
	// be rejected.
	Require2FA MWRequirements = 0x02
)

Middleware requirements

type MWRespondOnFailure

type MWRespondOnFailure int

MWRespondOnFailure tells authboss.Middleware how to respond to a failure to meet the requirements.

const (
	// RespondNotFound does not allow users who are not logged in to know a
	// route exists by responding with a 404.
	RespondNotFound MWRespondOnFailure = iota
	// RespondRedirect redirects users to the login page
	RespondRedirect
	// RespondUnauthorized provides a 401, this allows users to know the page
	// exists unlike the 404 option.
	RespondUnauthorized
)

Middleware response types

type Mailer

type Mailer interface {
	Send(context.Context, Email) error
}

Mailer is a type that is capable of sending an e-mail.

type Moduler

type Moduler interface {
	// Init the module
	Init(*Authboss) error
}

Moduler should be implemented by all the authboss modules.

type OAuth2Provider

type OAuth2Provider struct {
	OAuth2Config     *oauth2.Config
	AdditionalParams url.Values
	FindUserDetails  func(context.Context, oauth2.Config, *oauth2.Token) (map[string]string, error)
}

OAuth2Provider is the entire configuration required to authenticate with this provider.

The OAuth2Config does not need a redirect URL because it will be automatically created by the route registration in the oauth2 module.

AdditionalParams can be used to specify extra parameters to tack on to the end of the initial request, this allows for provider specific oauth options like access_type=offline to be passed to the provider.

FindUserDetails gives the config and the token allowing an http client using the authenticated token to be created, a call is then made to a known endpoint that will return details about the user we've retrieved the token for. Those details are returned as a map[string]string and subsequently passed into OAuth2ServerStorer.NewFromOAuth2. API this must be handled for each provider separately.

type OAuth2ServerStorer

type OAuth2ServerStorer interface {
	ServerStorer

	// NewFromOAuth2 should return an OAuth2User from a set
	// of details returned from OAuth2Provider.FindUserDetails
	// A more in-depth explanation is that once we've got an access token
	// for the service in question (say a service that rhymes with book)
	// the FindUserDetails function does an http request to a known endpoint
	// that provides details about the user, those details are captured in a
	// generic way as map[string]string and passed into this function to be
	// turned into a real user.
	//
	// It's possible that the user exists in the database already, and so
	// an attempt should be made to look that user up using the details.
	// Any details that have changed should be updated. Do not save the user
	// since that will be done later by OAuth2ServerStorer.SaveOAuth2()
	NewFromOAuth2(ctx context.Context, provider string, details map[string]string) (OAuth2User, error)

	// SaveOAuth2 has different semantics from the typical ServerStorer.Save,
	// in this case we want to insert a user if they do not exist.
	// The difference must be made clear because in the non-oauth2 case,
	// we know exactly when we want to Create vs Update. However since we're
	// simply trying to persist a user that may have been in our database,
	// but if not should already be (since you can think of the operation as
	// a caching of what's on the oauth2 provider's servers).
	SaveOAuth2(ctx context.Context, user OAuth2User) error
}

OAuth2ServerStorer has the ability to create users from data from the provider.

func EnsureCanOAuth2

func EnsureCanOAuth2(storer ServerStorer) OAuth2ServerStorer

EnsureCanOAuth2 makes sure the server storer supports oauth2 creation and lookup

type OAuth2User

type OAuth2User interface {
	User

	// IsOAuth2User checks to see if a user was registered in the site as an
	// oauth2 user.
	IsOAuth2User() bool

	GetOAuth2UID() (uid string)
	GetOAuth2Provider() (provider string)
	GetOAuth2AccessToken() (token string)
	GetOAuth2RefreshToken() (refreshToken string)
	GetOAuth2Expiry() (expiry time.Time)

	PutOAuth2UID(uid string)
	PutOAuth2Provider(provider string)
	PutOAuth2AccessToken(token string)
	PutOAuth2RefreshToken(refreshToken string)
	PutOAuth2Expiry(expiry time.Time)
}

OAuth2User allows reading and writing values relating to OAuth2 Also see MakeOAuthPID/ParseOAuthPID for helpers to fullfill the User part of the interface.

func MustBeOAuthable

func MustBeOAuthable(u User) OAuth2User

MustBeOAuthable forces an upgrade to an OAuth2User or panic.

type RecoverEndValuer

type RecoverEndValuer interface {
	Validator

	GetPassword() string
	GetToken() string
}

RecoverEndValuer is used to get data back from the final page of password recovery, the user will provide a password and it must be accompanied by the token to authorize the changing of that password. Contrary to the RecoverValuer, this should have validation errors for bad tokens.

func MustHaveRecoverEndValues

func MustHaveRecoverEndValues(v Validator) RecoverEndValuer

MustHaveRecoverEndValues upgrades a validatable set of values to ones specific to a user that needs to be recovered.

type RecoverMiddleValuer

type RecoverMiddleValuer interface {
	Validator

	GetToken() string
}

RecoverMiddleValuer provides the token that the user submitted via their link.

func MustHaveRecoverMiddleValues

func MustHaveRecoverMiddleValues(v Validator) RecoverMiddleValuer

MustHaveRecoverMiddleValues upgrades a validatable set of values to ones specific to a user that's attempting to recover.

type RecoverStartValuer

type RecoverStartValuer interface {
	Validator

	GetPID() string
}

RecoverStartValuer provides the PID entered by the user.

func MustHaveRecoverStartValues

func MustHaveRecoverStartValues(v Validator) RecoverStartValuer

MustHaveRecoverStartValues upgrades a validatable set of values to ones specific to a user that needs to be recovered.

type RecoverableUser

type RecoverableUser interface {
	AuthableUser

	GetEmail() (email string)
	GetRecoverSelector() (selector string)
	GetRecoverVerifier() (verifier string)
	GetRecoverExpiry() (expiry time.Time)

	PutEmail(email string)
	PutRecoverSelector(selector string)
	PutRecoverVerifier(verifier string)
	PutRecoverExpiry(expiry time.Time)
}

RecoverableUser is a user that can be recovered via e-mail

func MustBeRecoverable

func MustBeRecoverable(u User) RecoverableUser

MustBeRecoverable forces an upgrade to a RecoverableUser or panic.

type RecoveringServerStorer

type RecoveringServerStorer interface {
	ServerStorer

	// LoadByRecoverSelector finds a user by his recover selector field
	// and should return ErrUserNotFound if that user cannot be found.
	LoadByRecoverSelector(ctx context.Context, selector string) (RecoverableUser, error)
}

RecoveringServerStorer allows users to be recovered by a token

func EnsureCanRecover

func EnsureCanRecover(storer ServerStorer) RecoveringServerStorer

EnsureCanRecover makes sure the server storer supports confirm-lookup operations

type RedirectOptions

type RedirectOptions struct {
	// Success & Failure are used to set Flash messages / JSON messages
	// if set. They should be mutually exclusive.
	Success string
	Failure string

	// Code is used when it's an API request instead of 200.
	Code int

	// When a request should redirect a user somewhere on completion, these
	// should be set. RedirectURL tells it where to go. And optionally set
	// FollowRedirParam to override the RedirectURL if the form parameter
	// defined by FormValueRedirect is passed in the request.
	//
	// Redirecting works differently whether it's an API request or not.
	// If it's an API request, then it will leave the URL in a "redirect"
	// parameter.
	RedirectPath     string
	FollowRedirParam bool
}

RedirectOptions packages up all the pieces a module needs to write out a response.

type RememberValuer

type RememberValuer interface {

	// GetShouldRemember is the checkbox or what have you that
	// tells the remember module if it should remember that user's
	// authentication or not.
	GetShouldRemember() bool
}

RememberValuer allows auth/oauth2 to pass along the remember bool from the user to the remember module unobtrusively.

type RememberingServerStorer

type RememberingServerStorer interface {
	ServerStorer

	// AddRememberToken to a user
	AddRememberToken(ctx context.Context, pid, token string) error
	// DelRememberTokens removes all tokens for the given pid
	DelRememberTokens(ctx context.Context, pid string) error
	// UseRememberToken finds the pid-token pair and deletes it.
	// If the token could not be found return ErrTokenNotFound
	UseRememberToken(ctx context.Context, pid, token string) error
}

RememberingServerStorer allows users to be remembered across sessions

func EnsureCanRemember

func EnsureCanRemember(storer ServerStorer) RememberingServerStorer

EnsureCanRemember makes sure the server storer supports remember operations

type Renderer

type Renderer interface {
	// Load the given templates, will most likely be called multiple times
	Load(names ...string) error

	// Render the given template
	Render(ctx context.Context, page string, data HTMLData) (output []byte, contentType string, err error)
}

Renderer is a type that can render a given template with some data.

type RequestLogger

type RequestLogger interface {
	FromRequest(*http.Request) Logger
}

RequestLogger creates a logger from a request

type Router

type Router interface {
	http.Handler

	Get(path string, handler http.Handler)
	Post(path string, handler http.Handler)
	Delete(path string, handler http.Handler)
}

Router can register routes to later be used by the web application

type ServerStorer

type ServerStorer interface {
	// Load will look up the user based on the passed the PrimaryID
	Load(ctx context.Context, key string) (User, error)

	// Save persists the user in the database, this should never
	// create a user and instead return ErrUserNotFound if the user
	// does not exist.
	Save(ctx context.Context, user User) error
}

ServerStorer represents the data store that's capable of loading users and giving them a context with which to store themselves.

type UnderlyingResponseWriter

type UnderlyingResponseWriter interface {
	UnderlyingResponseWriter() http.ResponseWriter
}

UnderlyingResponseWriter retrieves the response writer underneath the current one. This allows us to wrap and later discover the particular one that we want. Keep in mind this should not be used to call the normal methods of a responsewriter, just additional ones particular to that type because it's possible to introduce subtle bugs otherwise.

type User

type User interface {
	GetPID() (pid string)
	PutPID(pid string)
}

User has functions for each piece of data it requires. Data should not be persisted on each function call. User has a PID (primary ID) that is used on the site as a single unique identifier to any given user (very typically e-mail or username).

User interfaces return no errors or bools to signal that a value was not present. Instead 0-value = null = not present, this puts the onus on Authboss code to check for this.

type UserValuer

type UserValuer interface {
	Validator

	GetPID() string
	GetPassword() string
}

UserValuer allows us to pull out the PID and Password from the request.

func MustHaveUserValues

func MustHaveUserValues(v Validator) UserValuer

MustHaveUserValues upgrades a validatable set of values to ones specific to an authenticating user.

type Validator

type Validator interface {
	// Validate makes the type validate itself and return
	// a list of validation errors.
	Validate() []error
}

Validator takes a form name and a set of inputs and returns any validation errors for the inputs.

Directories

Path Synopsis
Package auth implements password based user logins.
Package auth implements password based user logins.
Package confirm implements confirmation of user registration via e-mail
Package confirm implements confirmation of user registration via e-mail
Package defaults houses default implementations for the very many interfaces that authboss has.
Package defaults houses default implementations for the very many interfaces that authboss has.
Package expire helps expire user's logged in sessions
Package expire helps expire user's logged in sessions
Package lock implements user locking after N bad sign-in attempts.
Package lock implements user locking after N bad sign-in attempts.
Package logout allows users to log out (from auth or oauth2 logins)
Package logout allows users to log out (from auth or oauth2 logins)
Package mocks defines implemented interfaces for testing modules
Package mocks defines implemented interfaces for testing modules
Package oauth2 allows users to be created and authenticated via oauth2 services like facebook, google etc.
Package oauth2 allows users to be created and authenticated via oauth2 services like facebook, google etc.
otp
Package otp allows authentication through a one time password instead of a traditional password.
Package otp allows authentication through a one time password instead of a traditional password.
twofactor
Package twofactor allows authentication via one time passwords
Package twofactor allows authentication via one time passwords
twofactor/sms2fa
Package sms2fa implements two factor auth using sms-transmitted one time passwords.
Package sms2fa implements two factor auth using sms-transmitted one time passwords.
twofactor/totp2fa
Package totp2fa implements two factor auth using time-based one time passwords.
Package totp2fa implements two factor auth using time-based one time passwords.
Package recover implements password reset via e-mail.
Package recover implements password reset via e-mail.
Package register allows for user registration.
Package register allows for user registration.
Package remember implements persistent logins using cookies
Package remember implements persistent logins using cookies

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL