Bearer Token Auth
The Fundamentals middleware lesson introduced the short-circuit: write a
response and return before calling next, so a rejected request never
reaches the handler underneath. Chapter 5 built Recover, request logging,
and request IDs — middleware that lets every request through after doing
its work. This lesson is the other kind: middleware whose entire job is
deciding whether the request gets to continue at all.
The Authorization: Bearer <token> convention
HTTP defines the Authorization header for carrying credentials, and
Bearer is the scheme used almost everywhere token-based auth shows up —
APIs, OAuth, JWTs. The format is fixed: the literal word Bearer, a single
space, then the token itself. A client that wants in sends:
Authorization: Bearer sekret
Anything else — no header, a different scheme like Basic, a token that
doesn't match — means the request doesn't get through.
Parsing the header with strings.CutPrefix
Checking a fixed prefix and pulling out what follows is common enough that the standard library has a single function for it:
got, ok := strings.CutPrefix(r.Header.Get("Authorization"), "Bearer ")
CutPrefix returns the string with the prefix removed and a boolean
reporting whether the prefix was present. That boolean does double duty
here: it's false when the header is empty (an unset header reads as "",
which doesn't start with "Bearer ") and false when the client sent a
different scheme entirely. When it's true, got is exactly the token
portion, ready to compare. One call replaces a manual length check, a
substring, and a prefix comparison.
Short-circuit, then delegate
The middleware's structure is the same wrap-and-return shape from Chapter 5, but the decision now runs first and can end the request entirely:
func RequireToken(token string, next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
got, ok := strings.CutPrefix(r.Header.Get("Authorization"), "Bearer ")
if !ok || got != token {
http.Error(w, "unauthorized", http.StatusUnauthorized)
return
}
next.ServeHTTP(w, r)
})
}
Two conditions reject the request: the prefix wasn't there at all (!ok),
or it was there but the token doesn't match. Either way, http.Error writes
the 401 and the return stops execution before next.ServeHTTP is ever
reached. This is the same shape the Fundamentals auth-gate exercise
practiced — check a header, then either continue or stop — applied here to
a specific, widely used credential format instead of a generic API key.
Comparing tokens carefully
got != token is a plain string comparison, and for this lesson's purposes
that's fine: it's clear, it's correct, and the exercise grades on exactly
this behavior. Production services handling real secrets often reach for
crypto/subtle.ConstantTimeCompare instead, because Go's != on strings
can return as soon as it finds a differing byte — in principle, an attacker
measuring response timing across many requests could use that to guess a
secret one byte at a time. Whether that risk matters depends on what's
guarded and who's attacking it; it's worth knowing the tool exists, even
when a lesson-scale exercise doesn't require it.
Where auth sits in the chain
Auth middleware belongs early — wrapping close to the handler it protects,
but outside anything that shouldn't run for an unauthenticated caller.
Combined with Recover, logging, and request IDs from Chapter 5, a
realistic stack might read Recover(RequestID(Logging(RequireToken(token, mux)))), so every request gets a recovered panic and a log line even when
it's rejected, while only authenticated requests ever reach the mux.
Practice
1. Bearer Token Auth
IntermediateAuth is the archetypal middleware: check credentials, and either let the request through or stop it cold. Implement bearer-token auth.
RequireToken(token string, next http.Handler) http.Handler: the request must carryAuthorization: Bearer <token>where<token>equals the expectedtoken. If it matches, callnext. Otherwise respond401 Unauthorizedand do not callnext(a blocked request must never reach the handler).strings.CutPrefix(header, "Bearer ")gives you the token and an ok flag in one step — a missing header or wrong scheme fails theok, a wrong token fails the equality.package main import "net/http" // RequireToken wraps next, allowing the request through only when it carries // "Authorization: Bearer <token>" with the expected token. func RequireToken(token string, next http.Handler) http.Handler { // TODO: read the Authorization header, use strings.CutPrefix to strip // "Bearer " and get the token; if the prefix is missing or the token // doesn't match, respond 401 Unauthorized and return without calling // next. Otherwise call next. return next } func main() {}Sign in to write and run your solution in the browser.
Sign in for hints and the solution.