Ir para o conteúdo
Trilha
Capítulos

Referência

auth

Provider, Options, Auth, User e Store — a API do pacote auth, com os padrões e o que cada campo muda.

import "github.com/emersonjoe/trilha/auth" — login OpenID Connect com a biblioteca padrão. O pacote não registra rota: expõe manipuladores que o seu app/ publica.

Provedores#

func OIDC(issuer, clientID, clientSecret, redirectURL string) *Provider
func EntraID(tenant, clientID, clientSecret, redirectURL string) *Provider
func Keycloak(baseURL, realm, clientID, clientSecret, redirectURL string) *Provider
func Cognito(region, userPoolID, clientID, clientSecret, redirectURL string) *Provider
func Clerk(frontendAPI, clientID, clientSecret, redirectURL string) *Provider
ConstrutorEmissor resultantePapéis lidos de
OIDCo que você passarroles, groups
EntraIDhttps://login.microsoftonline.com/<tenant>/v2.0roles, groups, wids
Keycloak<baseURL>/realms/<realm>realm_access.roles, resource_access[clientID].roles
Cognitohttps://cognito-idp.<region>.amazonaws.com/<userPoolID>cognito:groups
Clerka Frontend API URL, normalizada (https://<slug>.clerk.accounts.dev)roles, groups — o id_token do Clerk traz a organização (org_id), não o papel nela; uma claim configurada entra em Options.RoleClaims

Provider.LogoutDomain existe por causa do Cognito: aponte-o para o domínio de managed login (<prefixo>.auth.<região>.amazoncognito.com, ou o seu próprio) e o Logout redireciona para /logout?client_id=…&logout_uri=… lá; a URL de retorno precisa estar nas Allowed sign-out URLs do app client. Vazio, o Logout apaga a sessão local, diz isso no log e não finge que federou. Os outros provedores ignoram o campo. O Clerk também não publica end_session_endpoint, e não tem endereço equivalente: lá o Logout é sempre local, e o log diz que a sessão do Clerk ficou de pé.

Provider.HTTPClient troca o cliente HTTP (padrão: 10 s de prazo). A descoberta é feita no primeiro uso e vale por uma hora; um emissor divergente entre a configuração e o documento é erro, não aviso.

Options#

CampoPadrãoO que faz
Scopes []stringopenid profile emailescopos pedidos ao provedor
Absolute time.Duration8 hprazo máximo da sessão, contado do login
Idle time.Duration30 minencerra sessão parada; IdleOff: true desliga
CookieName stringtrilha_sessionnome do cookie de sessão
LoginPath string/entrarpara onde Require manda um navegador anônimo
AfterLogin string/destino após o retorno, quando não há next
AfterLogout string/destino após o logout
RoleClaims []stringclaims adicionais de onde ler papéis
Store Storenilpersiste a sessão; nil = cookie assinado, sem estado

Auth#

func New(p *Provider, o Options) *Auth      // não faz rede
func (a *Auth) Start(c *trilha.Ctx) error   // → provedor (PKCE, state, nonce)
func (a *Auth) Callback(c *trilha.Ctx) error // valida o retorno e cria a sessão
func (a *Auth) Logout(c *trilha.Ctx) error   // apaga a sessão; RP-Initiated Logout quando existe
func (a *Auth) Require() trilha.MiddlewareFunc
func (a *Auth) RequireRole(roles ...string) trilha.MiddlewareFunc
func (a *Auth) Optional() trilha.MiddlewareFunc
func (a *Auth) User(c *trilha.Ctx) *User     // nil quando anônimo
func (a *Auth) Session(c *trilha.Ctx) (*User, error)

Require responde 302 para o login quando a requisição é uma navegação (Accept com text/html, fora de /api/) e 401 caso contrário. RequireRole responde 403 para quem está autenticado sem o papel. Basta um dos papéis listados; a comparação ignora maiúsculas.

User#

type User struct {
	Subject   string    // sub: o identificador estável
	Email     string    // email, ou preferred_username quando não há
	Name      string
	Roles     []string
	IssuedAt  time.Time // momento do login
	ExpiresAt time.Time
	Seen      time.Time // última atividade (janela de ociosidade)
	SessionID string    // muda a cada login
}

func (u *User) HasRole(role string) bool

Store#

type Store interface {
	Save(id string, u *User, ttl time.Duration) error
	Load(id string) (*User, bool)
	Delete(id string) error
}

func NewMemoryStore() *MemoryStore

Com um Store o cookie carrega apenas o identificador e o logout tem efeito imediato para todo mundo. MemoryStore vale para um processo só: réplicas não compartilham, e um reinício derruba todas as sessões. Para várias réplicas, implemente a interface sobre o seu banco ou cache.

Cookies#

CookieValidadeConteúdo
trilha_oidc_state10 minstate do pedido em curso
trilha_oidc_nonce10 minnonce do pedido em curso
trilha_oidc_verifier10 minverificador PKCE
trilha_oidc_next10 mindestino após o login (só caminho relativo)
trilha_sessionAbsolutea sessão (ou o id dela, com Store)

Todos são assinados (exigem TRILHA_SECRET), HttpOnly, SameSite=Lax e Secure sob HTTPS. Os quatro do fluxo são apagados no retorno, dê certo ou não.

Algoritmos aceitos#

RS256, RS384, RS512, ES256, ES384. A lista é fixa: o alg do token não escolhe nada. Chaves RSA com módulo menor que 2048 bits são ignoradas no JWKS, o kid é obrigatório, e a tolerância de relógio é de 60 segundos.

Auditoria#

trilha audit verifica, quando o projeto importa trilha/auth: segredo do cliente escrito no código (crítico) e redirect_uri em http:// fora de localhost (crítico).