oauth2-proxy/oauth2-proxy · error

failed to decode encryption secret

Error message

failed to decode encryption secret

What it means

Tickets carry the cookie secret used to encrypt the session as a base64url segment (ticketParts[2]). decodeTicketSecret decodes that segment; this error means the secret part is not valid base64 RawURL encoding, or the ticket encoding version is unrecognized so the default branch returns the bare error.

Source

Thrown at pkg/sessions/persistence/ticket.go:114

// to decode the ticket secret part based on the encoding version, or lack of it.
func decodeTicketSecret(ticketParts []string) ([]byte, error) {
	switch {
	case len(ticketParts) == 2:
		// old ticket encoding
		secret, err := base64.RawURLEncoding.DecodeString(ticketParts[1])
		if err != nil {
			return nil, fmt.Errorf("failed to decode encryption secret: %v", err)
		}
		return secret, nil
	case len(ticketParts) == 3 && ticketParts[0] == "v2":
		// new ticket encode
		secret, err := base64.RawURLEncoding.DecodeString(ticketParts[2])
		if err != nil {
			return nil, fmt.Errorf("failed to decode encryption secret: %v", err)
		}
		return secret, nil
	default:
		return nil, errors.New("failed to decode encryption secret")
	}
}

// decodeTicket decodes an encoded ticket string
func decodeTicket(encTicket string, cookieOpts *options.Cookie) (*ticket, error) {
	ticketParts := strings.Split(encTicket, ".")
	if len(ticketParts) != 2 && len(ticketParts) != 3 {
		return nil, errors.New("failed to decode ticket")
	}
	ticketID, errTicketID := decodeTicketID(ticketParts)
	if errTicketID != nil {
		return nil, fmt.Errorf("failed to decode ticket: %v", errTicketID)
	}
	secret, errSecret := decodeTicketSecret(ticketParts)
	if errSecret != nil {
		return nil, fmt.Errorf("failed to decode ticket: %v", errSecret)
	}
	return &ticket{

View on GitHub (pinned to 33c2eb92de)

Solutions

  1. Discard the corrupt ticket cookie and log in again to mint a new ticket.
  2. Verify the full 3-part ticket is intact (two dots, all segments non-empty).
  3. Check base64 segments are unpadded and URL-safe ('-'/'_' alphabet, no '=').
  4. Align oauth2-proxy versions across deployments so the ticket encoding format matches.
  5. If using Redis persistence, inspect the stored key for partial writes or encoding damage.
Defensive patterns

Strategy: validation

Validate before calling

func ticketSecretDecodable(v string) bool {
    parts := strings.Split(v, ".")
    if len(parts) != 3 {
        return false
    }
    _, err := base64.RawURLEncoding.DecodeString(parts[2])
    return err == nil
}

Try / catch

t, err := decodeTicket(encTicket, cookieOpts)
if err != nil {
    log.Printf("invalid ticket (%v); clearing session", err)
    return nil, sessions.ErrInvalidSession
}

Prevention

When it happens

Trigger: decodeTicket is called with a 3-part ticket whose third segment fails base64.RawURLEncoding.DecodeString, or a ticket with an unknown version prefix falls into the default case.

Common situations: Cookie truncated or corrupted in transit/storage; ticket value altered by manual copy/paste; version mismatch between the oauth2-proxy that wrote and the one reading the ticket (e.g. upgrade/downgrade mixing v1 format with legacy 2-part format).

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of oauth2-proxy/oauth2-proxy@33c2eb92de (2026-09-06). Data as JSON: /api/errors/67ecf230e30c934c. Report an issue: GitHub.