oidc

package
v2.2.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 27, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package oidc provides an implementation of the snowplow.TokenSource interface, allowing snowplow.Emitter to authenticate with the collector endpoint using the OIDC flow.

When executed within the supported cloud provider (AWS or Google Cloud), it will use cloud provider's API to generate an ID Token that the collector endpoint can use to authenticate the request, following the OIDC standard.

For that to work, the instance where this code will be executed needs to be properly prepared.

AWS setup

  1. Outbound Identity Federation must be explicitly enabled in the AWS Account's IAM settings.

  2. We need to create a specific permissions policy that allows talking to STS GetWebIdentityToken endpoint.

  3. The role that is assigned to the instance where the code will be running must include the above permission policy.

Policy definition:

 {
	"Version": "2012-10-17",
	"Statement": [
		{
			"Effect": "Allow",
			"Action": "sts:GetWebIdentityToken",
			"Resource": "*"
		}
	]
}

AWS ID Token validation

When properly executed in AWS, request to Snowplow Collector will be enhanced with a JWT used as the Authorization Bearer token.

First step of validation should be checking if it matches the Issued At (`iat`) and Expires At (`exp`) claims. Next, we should extract:

  • Key ID (`kid`) from the JWT header,
  • Issuer address (`iss`) from the JWT payload.

`iss` in AWS will point to a service that's unique for every AWS account where the request originated from. The URL should look like `https://some-uuid-here.tokens.sts.global.api.aws`. Therefore it's important that the authentication service on the collector side does extract the Issuer information and uses that to discover JWKS (JSON Web Key Set). There is no way to hardcode that information.

Once the Issuer is extracted, authentication service on the collector side can use the OIDC discovery URL to find the JWKS: `https://some-uuid-here.tokens.sts.global.api.aws/.well-known/openid-configuration`. This URL will return a JSON object with JWKS URL at the `jwks_uri` key.

From the JWKS we can next receive the public key by matching with `kid` retrieved from JWT header. Having the public key we can then validate signature of the JWT.

After validating JWT integrity, we can extract other claims to check if the token is authorized to talk with snowplow collector:

  • Audience (`aud`) - which snowplow.Emitter will set to the FQDN of the collector itself.
  • Subject (`sub`) - which should be the ARN of the role attached to the instance, scoped to the AWS account. This may be useful if we know that a single role from a single AWS account is expected to talk with snowplow collector.
  • Organization ID (`"https://sts.amazonaws.com/".org_id`) - which should be the ID of the AWS Organization the AWS account belongs to. This is useful if many roles from, potentially, many AWS Accounts but within the same AWS Organization are going to be talking with snowplow collector.

Google Cloud setup

  1. Service Account that is attached to the instance where the code will be executed, must have the `iam.serviceAccount.getOpenIdToken` permission enabled.

  2. When attaching the Service Account to the instance, you must enable the https://www.googleapis.com/auth/cloud-platform token scope.

Google Cloud ID Token validation

When properly executed in Google Cloud, request to Snowplow Collector will be enhanced with a JWT used as the Authorization Bearer token.

First step of validation should be checking if it matches the Issued At (`iat`) and Expires At (`exp`) claims. Next, we should extract:

  • Key ID (`kid`) from the JWT header,
  • Issuer address (`iss`) from the JWT payload.

`iss` in Google Cloud should always be set to https://accounts.google.com. Authentication service on the collector side can next use the OIDC discovery URL to find the JWKS (JSON Web Key Set): `https://accounts.google.com/.well-known/openid-configuration`. This URL will return a JSON object with JWKS URL at the `jwks_uri` key.

From the JWKS we can next receive the public key by matching with `kid` retrieved from JWT header. Having the public key we can then validate signature of the JWT.

After validating JWT integrity, we can extract other claims to check if the token is authorized to talk with snowplow collector:

  • Audience (`aud`) - which snowplow.Emitter will set to the FQDN of the collector itself.
  • Subject (`sub`) - which should be the numerical ID of the Service Account for which the token was generated. This may be useful if we know that a single service account is expected to talk with snowplow collector.
  • Organization Number (`google.organization_number`) - which should be the numerical ID of the Google Cloud Organization to which the service account belongs. This is useful if many service accounts from, potentially, many Google Cloud Projects but within the same Google Cloud Organization are going to be talking with snowplow collector.

Usage

To use Source, create the object and attach it to snowplow.Emitter using the snowplow.WithTokenSource() function:

ts := oidc.NewSource()

emitter, err := snowplow.NewEmitter(
	collectorURL,
	snowplow.WithTokenSource(ts),
)

If you want to configure Source, use the available Option functions when creating the Source object:

  ts := oidc.NewSource(
    oidc.WithSkipIfUnsupportedCloud(true) // to quietly ignore header enhancing if not running in supported cloud
  )

	emitter, err := snowplow.NewEmitter(
		collectorURL,
		snowplow.WithTokenSource(ts),
	)

Index

Constants

View Source
const (
	DefaultHTTPClientTimeout   = 15 * time.Second
	DefaultTokenCacheTTLBuffer = 1 * time.Minute
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Option

type Option func(*config)

Option is a type of function used to configure the Source.

func WithHTTPClientTimeout

func WithHTTPClientTimeout(t time.Duration) Option

WithHTTPClientTimeout allows to set a custom timeout of the HTTP Client that Source will use when talking with cloud provider API to generate the token. The default timeout is defined in the DefaultHTTPClientTimeout constant.

func WithSkipIfUnsupportedCloud

func WithSkipIfUnsupportedCloud(skip bool) Option

WithSkipIfUnsupportedCloud allows to attach Source to snowplow.Emitter and run the Emitter even if the application is not executed within the supported cloud. If that will happen, errors are ignored and the request header is simply not enhanced with the authorization token. By default, this is set to false, which means that if Source is used in snowplow.Emitter and the tracker is executed not on the supported cloud, events sending fails while trying to generate the authorization token.

func WithTokenCacheTTLBuffer

func WithTokenCacheTTLBuffer(t time.Duration) Option

WithTokenCacheTTLBuffer allows to define the buffer duration that will be used for caching the token generated from the STS. Generated JWT is parsed and from the expiration claim (`exp`) we subtract the duration provided with the TokenCacheTTLBuffer option. This ensures, that the token is rotated before it's expire, so last potential usage should be still valid. The default TTL Buffer is defined in the DefaultTokenCacheTTLBuffer constant.

type Source

type Source struct {
	// contains filtered or unexported fields
}

Source is the implementation of snowplow.TokenSource that detects if it's executed inside of one of the supported cloud providers and if yes - it uses their APIs to generate an OIDC ID Token which next can be used to authenticate with Snowplow collector endpoint.

func NewSource

func NewSource(opts ...Option) *Source

NewSource Creates a new Source object.

func (*Source) EnhanceHeader

func (ts *Source) EnhanceHeader(ctx context.Context, h http.Header, audience string) error

EnhanceHeader is the implementation of the snowplow.TokenSource interface.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL