Documentation ¶
Overview ¶
Package auth provides middleware and support for working with accounts within the context of an HTTP request, including getting accounts based on JWTs.
Index ¶
- Constants
- Variables
- func Decode(jwt []byte, secret []byte) (*jws.ClaimSet, error)
- func Encode(claimSet *jws.ClaimSet, secret []byte) ([]byte, error)
- func GetAccount(ctx context.Context, acct *account.Account) error
- func GetClaimSet(ctx context.Context, claimSet *jws.ClaimSet) error
- func Middleware(ctx context.Context, w http.ResponseWriter, r *http.Request) context.Context
- func Super(ctx context.Context, w http.ResponseWriter, r *http.Request) error
- func UseClaimSet(ctx context.Context, claimSet *jws.ClaimSet) error
- type AuthCheck
- type Checker
- type Error
Constants ¶
const ClaimSetCounterEntity = "APITokenCounter"
const ClaimSetCounterShards = 50
Variables ¶
var ( ExpiredJWTError = Error("JWT has expired") InvalidJWTError = Error("Not a valid JWT") BadSignatureError = Error("Signatures don't match") InvalidHeaderError = Error("Header isn't type JWT") InvalidAlgorithmError = Error("Algorithm isn't HS256") // SuperClaimSet is a special jws.ClaimSet returned when // the JWT supplied to a Decode call is actually just the // auth secret itself. A Super user can perform literally // any action it is possible to perform. SuperClaimSet = &jws.ClaimSet{ Sub: "_super", Exp: time.Now().AddDate(10, 0, 0).Unix(), } // NobodyClaimSet is a special jws.ClaimSet returned when // the JWT supplied to a Decode call is the empty string. NobodyClaimSet *jws.ClaimSet = &jws.ClaimSet{ Sub: "_nobody", Exp: time.Now().AddDate(10, 0, 0).Unix(), } )
var ( ErrForbidden = errors.New(http.StatusForbidden, "The account does not have permission to read the specified resource") ErrCannotGetAccount = errors.New(http.StatusUnauthorized, "There was an error retrieving the account to be authenticated. Please try again.") ErrCannotGetClaimSet = errors.New(http.StatusUnauthorized, "There was an error retrieving the claim set to be authenticated. Please try again.") ErrRoleMissing = errors.New(http.StatusForbidden, "The specified account does not have the specified role") ErrRoleNotInScope = errors.New(http.StatusUnauthorized, "The authentication token does not have the specified role in scope") ErrNotInAuthContext = errors.New(http.StatusInternalServerError, "That context object was not run through auth.Middleware!") ErrAccountIDDoesNotMatch = errors.New(http.StatusForbidden, "Account ID does not match route parameter") ErrInvalidConsumableClaimSet = errors.New(http.StatusForbidden, "Claimset has a u claim but not a jti claim") ErrClaimSetUsedUp = errors.New(http.StatusUnauthorized, "Claimset has been used up") )
var AllScope = "__ALL"
AllScope is the auth scope set when a token is valid for all of a user's roles.
Functions ¶
func Decode ¶
Decode checks jwt's signature against secret. If it matches and jwt has not expired, Decode returns a jws.ClaimSet containing jwt's claims.
There are two special cases:
- If jwt is equal to secret, SuperClaimSet is returned.
- If jwt is the empty string, NobodyClaimSet is returned.
func GetAccount ¶
GetAccount retrieves the authorized account for ctx and copies it into account. It returns the error if one was encountered.
func GetClaimSet ¶
GetClaimSet retrieves the authorized claimset for ctx and copies it into claimSet. It returns the error if one was encountered.
func Middleware ¶
Middleware sets up the request context so account information can be retrieved with auth.GetAccount(ctx). It panics if config.Get(ctx) fails.
Types ¶
type AuthCheck ¶
An AuthCheck is a handler-like function that determines whether a given HTTP request ought to be allowed to continue executing based on the request's authentication status. They can be used with Check to check credentials on a route without having to do so in the core HTTP handler for the route, which is very convenient.
func AccountMatchesParam ¶
AccountMatchesParam returns an AuthCheck that grants access if paramName is the same as the account's ID; so, for instance, on a route to /accounts/:accountId, with a request to /accounts/asdf, the AuthCheck will return true if the account's ID is asdf. As a special case, account.Nobody and account.Super will never match in this method.
type Checker ¶
type Checker struct {
// contains filtered or unexported fields
}
Checker is an object returned by auth.Check.
func Check ¶
Check produces a Checker for a set of AuthChecks. If none of the AuthChecks pass, Checker.Then will return a 403 to the user and prevent the underlying handler from being called.
func CheckAll ¶
CheckAll produces a Checker for a set of AuthChecks. If any of the AuthChecks fail, Checker.Then will return a 403 to the user and prevent the underlying handler from being called.
func (*Checker) Then ¶
func (c *Checker) Then(h kami.HandlerFunc) kami.HandlerFunc
Then produces a kami.Handler that wraps another handler with authentication magic. If every AuthCheck associated with the Checker fails, Then will reject the HTTP request with a 403. If only one of them passes, Then will call h. This produces a very pleasant syntax for authenticating routes:
func listAccounts(ctx context.Context, w http.ResponseWriter, r *http.Request) { w.Write([]byte("[]")) } kami.Get("/accounts", auth.Check(auth.Super, auth.HasRole("admin")).Then(listAccounts))
type Error ¶
type Error string
All errors returned by package auth have type Error, so they can be differentiated in a type switch as follows:
err := doSomethingInvolvingJWTs() switch t := err.(type) { case auth.Error: fmt.Println("Authentication error: ", err) default: fmt.Println("Generic error: ", err) }