feat: set more session and token-related span attributes

This commit is contained in:
Trong Huu Nguyen
2025-06-10 13:50:45 +02:00
parent 3813cd2ea3
commit bf2f97f400
5 changed files with 22 additions and 2 deletions

View File

@@ -15,6 +15,7 @@ import (
"github.com/lestrrat-go/jwx/v3/jws"
"github.com/lestrrat-go/jwx/v3/jwt"
"github.com/nais/wonderwall/pkg/retry"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
"golang.org/x/oauth2"
@@ -117,6 +118,7 @@ func (c *Client) RefreshGrant(ctx context.Context, refreshToken, previousIDToken
if err := json.Unmarshal(body, &tokenResponse); err != nil {
return nil, fmt.Errorf("unmarshalling token response: %w", err)
}
span.SetAttributes(attribute.Int64("oauth.token_expires_in_seconds", tokenResponse.ExpiresIn))
// id_tokens may not always be returned from a refresh grant (OpenID Connect Core 12.1)
if tokenResponse.IDToken != "" {
@@ -127,6 +129,8 @@ func (c *Client) RefreshGrant(ctx context.Context, refreshToken, previousIDToken
err = openid.ValidateRefreshedIDToken(c.cfg, previousIDToken, tokenResponse.IDToken, expectedAcr, jwkSet)
if err != nil {
span.SetAttributes(attribute.Bool("oauth.valid_id_token", false))
otel.AddErrorEvent(span, "refreshGrantError", "invalidIDToken", err)
if errors.Is(err, jws.VerificationError()) {
// JWKS might not be up to date, so we'll want to force a refresh for the next attempt
_, _ = c.jwksProvider.RefreshPublicJwkSet(ctx)

View File

@@ -89,6 +89,7 @@ func (c *Client) redeemTokens(ctx context.Context, code string, cookie *openid.L
if err != nil {
return nil, fmt.Errorf("exchanging authorization code for token: %w", err)
}
span.SetAttributes(attribute.Int64("oauth.token_expires_in_seconds", rawTokens.ExpiresIn))
jwkSet, err := c.jwksProvider.GetPublicJwkSet(ctx)
if err != nil {

View File

@@ -8,6 +8,8 @@ import (
"github.com/nais/wonderwall/internal/crypto"
"github.com/nais/wonderwall/pkg/openid"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
)
const (
@@ -270,6 +272,16 @@ func (in *Metadata) Verbose() MetadataVerbose {
}
}
func (in *Metadata) SetSpanAttributes(span trace.Span) {
span.SetAttributes(attribute.String("session.token_expires_at", in.Tokens.ExpireAt.Format(time.RFC3339)))
span.SetAttributes(attribute.String("session.token_refreshed_at", in.Tokens.RefreshedAt.Format(time.RFC3339)))
span.SetAttributes(attribute.String("session.created_at", in.Session.CreatedAt.Format(time.RFC3339)))
span.SetAttributes(attribute.String("session.ends_at", in.Session.EndsAt.Format(time.RFC3339)))
if !in.Session.TimeoutAt.IsZero() {
span.SetAttributes(attribute.String("session.timeout_at", in.Session.TimeoutAt.Format(time.RFC3339)))
}
}
type MetadataVerbose struct {
Session MetadataSessionVerbose `json:"session"`
Tokens MetadataTokensVerbose `json:"tokens"`

View File

@@ -96,6 +96,7 @@ func (in *manager) Create(r *http.Request, tokens *openid.Tokens, sessionLifetim
sess := NewSession(data, ticket)
span.SetAttributes(attribute.Bool("session.created", true))
span.SetAttributes(attribute.String("session.id", sess.ExternalSessionID()))
data.Metadata.SetSpanAttributes(span)
return sess, nil
}
@@ -117,7 +118,6 @@ func (in *manager) DeleteForExternalID(ctx context.Context, id string) error {
func (in *manager) GetOrRefresh(r *http.Request) (*Session, error) {
r, span := otel.StartSpanFromRequest(r, "Session.GetOrRefresh")
defer span.End()
span.SetAttributes(attribute.Bool("session.refreshed", false))
sess, err := in.Get(r)
if err != nil {
@@ -128,9 +128,9 @@ func (in *manager) GetOrRefresh(r *http.Request) (*Session, error) {
return sess, nil
}
span.SetAttributes(attribute.Bool("session.should_refresh", true))
refreshed, err := in.Refresh(r, sess)
if err == nil {
span.SetAttributes(attribute.Bool("session.refreshed", true))
return refreshed, nil
}
@@ -233,6 +233,8 @@ func (in *manager) Refresh(r *http.Request, sess *Session) (*Session, error) {
sess.data.AccessToken = resp.AccessToken
sess.data.RefreshToken = resp.RefreshToken
sess.data.Metadata.Refresh(resp.ExpiresIn)
span.SetAttributes(attribute.String("session.token_expires_at", sess.data.Metadata.Tokens.ExpireAt.Format(time.RFC3339)))
span.SetAttributes(attribute.String("session.token_refreshed_at", sess.data.Metadata.Tokens.RefreshedAt.Format(time.RFC3339)))
if in.cfg.Session.Inactivity {
sess.data.Metadata.WithTimeout(in.cfg.Session.InactivityTimeout)

View File

@@ -80,5 +80,6 @@ func (in *reader) getForTicket(ctx context.Context, ticket *Ticket) (*Session, e
}
span.SetAttributes(attribute.Bool("session.valid_session", true))
data.Metadata.SetSpanAttributes(span)
return sess, nil
}