The Security Context

One of the biggest challenges in Go web development is accessing the authenticated user deep within your service layer. Often, developers resort to passing the user object or the HTTP Request context through dozens of function calls.

Rays Web Security solves this using github.com/timandy/routine to establish a ThreadLocal SecurityContext within its internal implementations.

Accessing the Authenticated User

Whenever an authenticated request is being processed, the framework automatically binds the Authentication object to the current goroutine.

Because the interfaces are exposed in pkg/core, you can inject the SecurityContextHolder interface directly into any of your Beams and access the context from anywhere in your application without passing it down the call stack.

package services

import (
    "fmt"
    . "github.com/BeamFoundry/rays-web-security/pkg/core"
    . "github.com/BeamFoundry/rays/pkg/core"
    . "github.com/BeamFoundry/rays/pkg/lang"
)

type OrderService struct {
    Service
    orderRepo             *OrderRepository      `@:"Inject"`
    securityContextHolder SecurityContextHolder `@:"Inject"` // Properly injected interface
}

func (this *OrderService) PlaceOrder(cart Cart) Error {

    // Retrieve the context using the injected holder for the current thread
    auth := this.securityContextHolder.GetContext().GetAuthentication()

    if auth == nil || !auth.IsAuthenticated() {
        return NewError("Unauthorized", "You must be logged in to place an order")
    }

    // Safely cast the principal back to your domain model
    currentUser := auth.GetPrincipal().(*models.User)

    fmt.Printf("User %s is placing an order for %v\n", currentUser.Email, cart.Total)

    // ... process order ...
    return nil
}