From 88aab2860386c7e598bb6df4ee75b2dc411f916c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20M=C3=B6hlmann?= Date: Fri, 17 Mar 2023 17:30:58 +0200 Subject: [PATCH] use type aliases for oidc.Verifier this binds the correct contstructor to each verifier usecase. --- pkg/client/rp/relying_party.go | 8 ++++---- pkg/client/rp/verifier.go | 28 ++++++++++++++------------- pkg/client/rp/verifier_test.go | 8 ++++---- pkg/op/auth_request.go | 8 ++++---- pkg/op/auth_request_test.go | 2 +- pkg/op/mock/authorizer.mock.go | 5 ++--- pkg/op/mock/authorizer.mock.impl.go | 2 +- pkg/op/op.go | 8 ++++---- pkg/op/session.go | 2 +- pkg/op/token_intospection.go | 2 +- pkg/op/token_request.go | 4 ++-- pkg/op/token_revocation.go | 2 +- pkg/op/userinfo.go | 2 +- pkg/op/verifier_access_token.go | 14 ++++++++------ pkg/op/verifier_access_token_test.go | 8 ++++---- pkg/op/verifier_id_token_hint.go | 12 +++++++----- pkg/op/verifier_id_token_hint_test.go | 8 ++++---- 17 files changed, 64 insertions(+), 59 deletions(-) diff --git a/pkg/client/rp/relying_party.go b/pkg/client/rp/relying_party.go index b9e395d..bd96e16 100644 --- a/pkg/client/rp/relying_party.go +++ b/pkg/client/rp/relying_party.go @@ -63,8 +63,8 @@ type RelyingParty interface { // be used to start a DeviceAuthorization flow. GetDeviceAuthorizationEndpoint() string - // IDTokenVerifier returns the verifier interface used for oidc id_token verification - IDTokenVerifier() *oidc.Verifier + // IDTokenVerifier returns the verifier used for oidc id_token verification + IDTokenVerifier() *IDTokenVerifier // ErrorHandler returns the handler used for callback errors ErrorHandler() func(http.ResponseWriter, *http.Request, string, string, string) @@ -88,7 +88,7 @@ type relyingParty struct { cookieHandler *httphelper.CookieHandler errorHandler func(http.ResponseWriter, *http.Request, string, string, string) - idTokenVerifier *oidc.Verifier + idTokenVerifier *IDTokenVerifier verifierOpts []VerifierOption signer jose.Signer } @@ -137,7 +137,7 @@ func (rp *relyingParty) GetRevokeEndpoint() string { return rp.endpoints.RevokeURL } -func (rp *relyingParty) IDTokenVerifier() *oidc.Verifier { +func (rp *relyingParty) IDTokenVerifier() *IDTokenVerifier { if rp.idTokenVerifier == nil { rp.idTokenVerifier = NewIDTokenVerifier(rp.issuer, rp.oauthConfig.ClientID, NewRemoteKeySet(rp.httpClient, rp.endpoints.JKWsURL), rp.verifierOpts...) } diff --git a/pkg/client/rp/verifier.go b/pkg/client/rp/verifier.go index 58c7c0f..3294f40 100644 --- a/pkg/client/rp/verifier.go +++ b/pkg/client/rp/verifier.go @@ -11,7 +11,7 @@ import ( // VerifyTokens implement the Token Response Validation as defined in OIDC specification // https://openid.net/specs/openid-connect-core-1_0.html#TokenResponseValidation -func VerifyTokens[C oidc.IDClaims](ctx context.Context, accessToken, idToken string, v *oidc.Verifier) (claims C, err error) { +func VerifyTokens[C oidc.IDClaims](ctx context.Context, accessToken, idToken string, v *IDTokenVerifier) (claims C, err error) { var nilClaims C claims, err = VerifyIDToken[C](ctx, idToken, v) @@ -26,7 +26,7 @@ func VerifyTokens[C oidc.IDClaims](ctx context.Context, accessToken, idToken str // VerifyIDToken validates the id token according to // https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation -func VerifyIDToken[C oidc.Claims](ctx context.Context, token string, v *oidc.Verifier) (claims C, err error) { +func VerifyIDToken[C oidc.Claims](ctx context.Context, token string, v *IDTokenVerifier) (claims C, err error) { var nilClaims C decrypted, err := oidc.DecryptToken(token) @@ -80,6 +80,8 @@ func VerifyIDToken[C oidc.Claims](ctx context.Context, token string, v *oidc.Ver return claims, nil } +type IDTokenVerifier oidc.Verifier + // VerifyAccessToken validates the access token according to // https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowTokenValidation func VerifyAccessToken(accessToken, atHash string, sigAlgorithm jose.SignatureAlgorithm) error { @@ -98,8 +100,8 @@ func VerifyAccessToken(accessToken, atHash string, sigAlgorithm jose.SignatureAl } // NewIDTokenVerifier returns a oidc.Verifier suitable for ID token verification. -func NewIDTokenVerifier(issuer, clientID string, keySet oidc.KeySet, options ...VerifierOption) *oidc.Verifier { - v := &oidc.Verifier{ +func NewIDTokenVerifier(issuer, clientID string, keySet oidc.KeySet, options ...VerifierOption) *IDTokenVerifier { + v := &IDTokenVerifier{ Issuer: issuer, ClientID: clientID, KeySet: keySet, @@ -117,47 +119,47 @@ func NewIDTokenVerifier(issuer, clientID string, keySet oidc.KeySet, options ... } // VerifierOption is the type for providing dynamic options to the IDTokenVerifier -type VerifierOption func(*oidc.Verifier) +type VerifierOption func(*IDTokenVerifier) // WithIssuedAtOffset mitigates the risk of iat to be in the future // because of clock skews with the ability to add an offset to the current time -func WithIssuedAtOffset(offset time.Duration) func(*oidc.Verifier) { - return func(v *oidc.Verifier) { +func WithIssuedAtOffset(offset time.Duration) VerifierOption { + return func(v *IDTokenVerifier) { v.Offset = offset } } // WithIssuedAtMaxAge provides the ability to define the maximum duration between iat and now -func WithIssuedAtMaxAge(maxAge time.Duration) func(*oidc.Verifier) { - return func(v *oidc.Verifier) { +func WithIssuedAtMaxAge(maxAge time.Duration) VerifierOption { + return func(v *IDTokenVerifier) { v.MaxAgeIAT = maxAge } } // WithNonce sets the function to check the nonce func WithNonce(nonce func(context.Context) string) VerifierOption { - return func(v *oidc.Verifier) { + return func(v *IDTokenVerifier) { v.Nonce = nonce } } // WithACRVerifier sets the verifier for the acr claim func WithACRVerifier(verifier oidc.ACRVerifier) VerifierOption { - return func(v *oidc.Verifier) { + return func(v *IDTokenVerifier) { v.ACR = verifier } } // WithAuthTimeMaxAge provides the ability to define the maximum duration between auth_time and now func WithAuthTimeMaxAge(maxAge time.Duration) VerifierOption { - return func(v *oidc.Verifier) { + return func(v *IDTokenVerifier) { v.MaxAge = maxAge } } // WithSupportedSigningAlgorithms overwrites the default RS256 signing algorithm func WithSupportedSigningAlgorithms(algs ...string) VerifierOption { - return func(v *oidc.Verifier) { + return func(v *IDTokenVerifier) { v.SupportedSignAlgs = algs } } diff --git a/pkg/client/rp/verifier_test.go b/pkg/client/rp/verifier_test.go index 7757b5c..11bf2f9 100644 --- a/pkg/client/rp/verifier_test.go +++ b/pkg/client/rp/verifier_test.go @@ -13,7 +13,7 @@ import ( ) func TestVerifyTokens(t *testing.T) { - verifier := &oidc.Verifier{ + verifier := &IDTokenVerifier{ Issuer: tu.ValidIssuer, MaxAgeIAT: 2 * time.Minute, Offset: time.Second, @@ -91,7 +91,7 @@ func TestVerifyTokens(t *testing.T) { } func TestVerifyIDToken(t *testing.T) { - verifier := &oidc.Verifier{ + verifier := &IDTokenVerifier{ Issuer: tu.ValidIssuer, MaxAgeIAT: 2 * time.Minute, Offset: time.Second, @@ -300,7 +300,7 @@ func TestNewIDTokenVerifier(t *testing.T) { tests := []struct { name string args args - want *oidc.Verifier + want *IDTokenVerifier }{ { name: "nil nonce", // otherwise assert.Equal will fail on the function @@ -317,7 +317,7 @@ func TestNewIDTokenVerifier(t *testing.T) { WithSupportedSigningAlgorithms("ABC", "DEF"), }, }, - want: &oidc.Verifier{ + want: &IDTokenVerifier{ Issuer: tu.ValidIssuer, Offset: time.Minute, MaxAgeIAT: time.Hour, diff --git a/pkg/op/auth_request.go b/pkg/op/auth_request.go index 134d423..b516909 100644 --- a/pkg/op/auth_request.go +++ b/pkg/op/auth_request.go @@ -38,7 +38,7 @@ type Authorizer interface { Storage() Storage Decoder() httphelper.Decoder Encoder() httphelper.Encoder - IDTokenHintVerifier(context.Context) *oidc.Verifier + IDTokenHintVerifier(context.Context) *IDTokenHintVerifier Crypto() Crypto RequestObjectSupported() bool } @@ -47,7 +47,7 @@ type Authorizer interface { // implementing its own validation mechanism for the auth request type AuthorizeValidator interface { Authorizer - ValidateAuthRequest(context.Context, *oidc.AuthRequest, Storage, *oidc.Verifier) (string, error) + ValidateAuthRequest(context.Context, *oidc.AuthRequest, Storage, *IDTokenHintVerifier) (string, error) } func authorizeHandler(authorizer Authorizer) func(http.ResponseWriter, *http.Request) { @@ -204,7 +204,7 @@ func CopyRequestObjectToAuthRequest(authReq *oidc.AuthRequest, requestObject *oi } // ValidateAuthRequest validates the authorize parameters and returns the userID of the id_token_hint if passed -func ValidateAuthRequest(ctx context.Context, authReq *oidc.AuthRequest, storage Storage, verifier *oidc.Verifier) (sub string, err error) { +func ValidateAuthRequest(ctx context.Context, authReq *oidc.AuthRequest, storage Storage, verifier *IDTokenHintVerifier) (sub string, err error) { authReq.MaxAge, err = ValidateAuthReqPrompt(authReq.Prompt, authReq.MaxAge) if err != nil { return "", err @@ -384,7 +384,7 @@ func ValidateAuthReqResponseType(client Client, responseType oidc.ResponseType) // ValidateAuthReqIDTokenHint validates the id_token_hint (if passed as parameter in the request) // and returns the `sub` claim -func ValidateAuthReqIDTokenHint(ctx context.Context, idTokenHint string, verifier *oidc.Verifier) (string, error) { +func ValidateAuthReqIDTokenHint(ctx context.Context, idTokenHint string, verifier *IDTokenHintVerifier) (string, error) { if idTokenHint == "" { return "", nil } diff --git a/pkg/op/auth_request_test.go b/pkg/op/auth_request_test.go index f2a4a9d..53fa9d3 100644 --- a/pkg/op/auth_request_test.go +++ b/pkg/op/auth_request_test.go @@ -146,7 +146,7 @@ func TestValidateAuthRequest(t *testing.T) { type args struct { authRequest *oidc.AuthRequest storage op.Storage - verifier *oidc.Verifier + verifier *op.IDTokenHintVerifier } tests := []struct { name string diff --git a/pkg/op/mock/authorizer.mock.go b/pkg/op/mock/authorizer.mock.go index 076b8ae..a0c67e3 100644 --- a/pkg/op/mock/authorizer.mock.go +++ b/pkg/op/mock/authorizer.mock.go @@ -11,7 +11,6 @@ import ( gomock "github.com/golang/mock/gomock" http "github.com/zitadel/oidc/v3/pkg/http" op "github.com/zitadel/oidc/v3/pkg/op" - oidc "github.com/zitadel/oidc/v3/pkg/oidc" ) // MockAuthorizer is a mock of Authorizer interface. @@ -80,10 +79,10 @@ func (mr *MockAuthorizerMockRecorder) Encoder() *gomock.Call { } // IDTokenHintVerifier mocks base method. -func (m *MockAuthorizer) IDTokenHintVerifier(arg0 context.Context) *oidc.Verifier { +func (m *MockAuthorizer) IDTokenHintVerifier(arg0 context.Context) *op.IDTokenHintVerifier { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "IDTokenHintVerifier", arg0) - ret0, _ := ret[0].(*oidc.Verifier) + ret0, _ := ret[0].(*op.IDTokenHintVerifier) return ret0 } diff --git a/pkg/op/mock/authorizer.mock.impl.go b/pkg/op/mock/authorizer.mock.impl.go index 88e54b6..409683a 100644 --- a/pkg/op/mock/authorizer.mock.impl.go +++ b/pkg/op/mock/authorizer.mock.impl.go @@ -49,7 +49,7 @@ func ExpectEncoder(a op.Authorizer) { func ExpectVerifier(a op.Authorizer, t *testing.T) { mockA := a.(*MockAuthorizer) mockA.EXPECT().IDTokenHintVerifier(gomock.Any()).DoAndReturn( - func() *oidc.Verifier { + func() *op.IDTokenHintVerifier { return op.NewIDTokenHintVerifier("", nil) }) } diff --git a/pkg/op/op.go b/pkg/op/op.go index 45a5597..9ed5662 100644 --- a/pkg/op/op.go +++ b/pkg/op/op.go @@ -73,8 +73,8 @@ type OpenIDProvider interface { Storage() Storage Decoder() httphelper.Decoder Encoder() httphelper.Encoder - IDTokenHintVerifier(context.Context) *oidc.Verifier - AccessTokenVerifier(context.Context) *oidc.Verifier + IDTokenHintVerifier(context.Context) *IDTokenHintVerifier + AccessTokenVerifier(context.Context) *AccessTokenVerifier Crypto() Crypto DefaultLogoutRedirectURI() string Probes() []ProbesFn @@ -342,7 +342,7 @@ func (o *Provider) Encoder() httphelper.Encoder { return o.encoder } -func (o *Provider) IDTokenHintVerifier(ctx context.Context) *oidc.Verifier { +func (o *Provider) IDTokenHintVerifier(ctx context.Context) *IDTokenHintVerifier { return NewIDTokenHintVerifier(IssuerFromContext(ctx), o.openIDKeySet(), o.idTokenHintVerifierOpts...) } @@ -350,7 +350,7 @@ func (o *Provider) JWTProfileVerifier(ctx context.Context) *JWTProfileVerifier { return NewJWTProfileVerifier(o.Storage(), IssuerFromContext(ctx), 1*time.Hour, time.Second) } -func (o *Provider) AccessTokenVerifier(ctx context.Context) *oidc.Verifier { +func (o *Provider) AccessTokenVerifier(ctx context.Context) *AccessTokenVerifier { return NewAccessTokenVerifier(IssuerFromContext(ctx), o.openIDKeySet(), o.accessTokenVerifierOpts...) } diff --git a/pkg/op/session.go b/pkg/op/session.go index 22c5138..fd914d1 100644 --- a/pkg/op/session.go +++ b/pkg/op/session.go @@ -13,7 +13,7 @@ import ( type SessionEnder interface { Decoder() httphelper.Decoder Storage() Storage - IDTokenHintVerifier(context.Context) *oidc.Verifier + IDTokenHintVerifier(context.Context) *IDTokenHintVerifier DefaultLogoutRedirectURI() string } diff --git a/pkg/op/token_intospection.go b/pkg/op/token_intospection.go index a1d9c74..21b79c3 100644 --- a/pkg/op/token_intospection.go +++ b/pkg/op/token_intospection.go @@ -13,7 +13,7 @@ type Introspector interface { Decoder() httphelper.Decoder Crypto() Crypto Storage() Storage - AccessTokenVerifier(context.Context) *oidc.Verifier + AccessTokenVerifier(context.Context) *AccessTokenVerifier } type IntrospectorJWTProfile interface { diff --git a/pkg/op/token_request.go b/pkg/op/token_request.go index 0749452..c06a51b 100644 --- a/pkg/op/token_request.go +++ b/pkg/op/token_request.go @@ -20,8 +20,8 @@ type Exchanger interface { GrantTypeJWTAuthorizationSupported() bool GrantTypeClientCredentialsSupported() bool GrantTypeDeviceCodeSupported() bool - AccessTokenVerifier(context.Context) *oidc.Verifier - IDTokenHintVerifier(context.Context) *oidc.Verifier + AccessTokenVerifier(context.Context) *AccessTokenVerifier + IDTokenHintVerifier(context.Context) *IDTokenHintVerifier } func tokenHandler(exchanger Exchanger) func(w http.ResponseWriter, r *http.Request) { diff --git a/pkg/op/token_revocation.go b/pkg/op/token_revocation.go index d7ac82b..fd1ee93 100644 --- a/pkg/op/token_revocation.go +++ b/pkg/op/token_revocation.go @@ -15,7 +15,7 @@ type Revoker interface { Decoder() httphelper.Decoder Crypto() Crypto Storage() Storage - AccessTokenVerifier(context.Context) *oidc.Verifier + AccessTokenVerifier(context.Context) *AccessTokenVerifier AuthMethodPrivateKeyJWTSupported() bool AuthMethodPostSupported() bool } diff --git a/pkg/op/userinfo.go b/pkg/op/userinfo.go index 68b3497..86205b5 100644 --- a/pkg/op/userinfo.go +++ b/pkg/op/userinfo.go @@ -14,7 +14,7 @@ type UserinfoProvider interface { Decoder() httphelper.Decoder Crypto() Crypto Storage() Storage - AccessTokenVerifier(context.Context) *oidc.Verifier + AccessTokenVerifier(context.Context) *AccessTokenVerifier } func userinfoHandler(userinfoProvider UserinfoProvider) func(http.ResponseWriter, *http.Request) { diff --git a/pkg/op/verifier_access_token.go b/pkg/op/verifier_access_token.go index 17bbfed..120bfa7 100644 --- a/pkg/op/verifier_access_token.go +++ b/pkg/op/verifier_access_token.go @@ -6,17 +6,19 @@ import ( "github.com/zitadel/oidc/v3/pkg/oidc" ) -type AccessTokenVerifierOpt func(*oidc.Verifier) +type AccessTokenVerifier oidc.Verifier + +type AccessTokenVerifierOpt func(*AccessTokenVerifier) func WithSupportedAccessTokenSigningAlgorithms(algs ...string) AccessTokenVerifierOpt { - return func(verifier *oidc.Verifier) { + return func(verifier *AccessTokenVerifier) { verifier.SupportedSignAlgs = algs } } -// NewAccessTokenVerifier returns a oidc.Verifier suitable for access token verification. -func NewAccessTokenVerifier(issuer string, keySet oidc.KeySet, opts ...AccessTokenVerifierOpt) *oidc.Verifier { - verifier := &oidc.Verifier{ +// NewAccessTokenVerifier returns a AccessTokenVerifier suitable for access token verification. +func NewAccessTokenVerifier(issuer string, keySet oidc.KeySet, opts ...AccessTokenVerifierOpt) *AccessTokenVerifier { + verifier := &AccessTokenVerifier{ Issuer: issuer, KeySet: keySet, } @@ -27,7 +29,7 @@ func NewAccessTokenVerifier(issuer string, keySet oidc.KeySet, opts ...AccessTok } // VerifyAccessToken validates the access token (issuer, signature and expiration). -func VerifyAccessToken[C oidc.Claims](ctx context.Context, token string, v *oidc.Verifier) (claims C, err error) { +func VerifyAccessToken[C oidc.Claims](ctx context.Context, token string, v *AccessTokenVerifier) (claims C, err error) { var nilClaims C decrypted, err := oidc.DecryptToken(token) diff --git a/pkg/op/verifier_access_token_test.go b/pkg/op/verifier_access_token_test.go index b32039a..66e32ce 100644 --- a/pkg/op/verifier_access_token_test.go +++ b/pkg/op/verifier_access_token_test.go @@ -20,7 +20,7 @@ func TestNewAccessTokenVerifier(t *testing.T) { tests := []struct { name string args args - want *oidc.Verifier + want *AccessTokenVerifier }{ { name: "simple", @@ -28,7 +28,7 @@ func TestNewAccessTokenVerifier(t *testing.T) { issuer: tu.ValidIssuer, keySet: tu.KeySet{}, }, - want: &oidc.Verifier{ + want: &AccessTokenVerifier{ Issuer: tu.ValidIssuer, KeySet: tu.KeySet{}, }, @@ -42,7 +42,7 @@ func TestNewAccessTokenVerifier(t *testing.T) { WithSupportedAccessTokenSigningAlgorithms("ABC", "DEF"), }, }, - want: &oidc.Verifier{ + want: &AccessTokenVerifier{ Issuer: tu.ValidIssuer, KeySet: tu.KeySet{}, SupportedSignAlgs: []string{"ABC", "DEF"}, @@ -58,7 +58,7 @@ func TestNewAccessTokenVerifier(t *testing.T) { } func TestVerifyAccessToken(t *testing.T) { - verifier := &oidc.Verifier{ + verifier := &AccessTokenVerifier{ Issuer: tu.ValidIssuer, MaxAgeIAT: 2 * time.Minute, Offset: time.Second, diff --git a/pkg/op/verifier_id_token_hint.go b/pkg/op/verifier_id_token_hint.go index 5c2c7e1..6143252 100644 --- a/pkg/op/verifier_id_token_hint.go +++ b/pkg/op/verifier_id_token_hint.go @@ -6,16 +6,18 @@ import ( "github.com/zitadel/oidc/v3/pkg/oidc" ) -type IDTokenHintVerifierOpt func(*oidc.Verifier) +type IDTokenHintVerifier oidc.Verifier + +type IDTokenHintVerifierOpt func(*IDTokenHintVerifier) func WithSupportedIDTokenHintSigningAlgorithms(algs ...string) IDTokenHintVerifierOpt { - return func(verifier *oidc.Verifier) { + return func(verifier *IDTokenHintVerifier) { verifier.SupportedSignAlgs = algs } } -func NewIDTokenHintVerifier(issuer string, keySet oidc.KeySet, opts ...IDTokenHintVerifierOpt) *oidc.Verifier { - verifier := &oidc.Verifier{ +func NewIDTokenHintVerifier(issuer string, keySet oidc.KeySet, opts ...IDTokenHintVerifierOpt) *IDTokenHintVerifier { + verifier := &IDTokenHintVerifier{ Issuer: issuer, KeySet: keySet, } @@ -27,7 +29,7 @@ func NewIDTokenHintVerifier(issuer string, keySet oidc.KeySet, opts ...IDTokenHi // VerifyIDTokenHint validates the id token according to // https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation -func VerifyIDTokenHint[C oidc.Claims](ctx context.Context, token string, v *oidc.Verifier) (claims C, err error) { +func VerifyIDTokenHint[C oidc.Claims](ctx context.Context, token string, v *IDTokenHintVerifier) (claims C, err error) { var nilClaims C decrypted, err := oidc.DecryptToken(token) diff --git a/pkg/op/verifier_id_token_hint_test.go b/pkg/op/verifier_id_token_hint_test.go index deb3528..e514a76 100644 --- a/pkg/op/verifier_id_token_hint_test.go +++ b/pkg/op/verifier_id_token_hint_test.go @@ -20,7 +20,7 @@ func TestNewIDTokenHintVerifier(t *testing.T) { tests := []struct { name string args args - want *oidc.Verifier + want *IDTokenHintVerifier }{ { name: "simple", @@ -28,7 +28,7 @@ func TestNewIDTokenHintVerifier(t *testing.T) { issuer: tu.ValidIssuer, keySet: tu.KeySet{}, }, - want: &oidc.Verifier{ + want: &IDTokenHintVerifier{ Issuer: tu.ValidIssuer, KeySet: tu.KeySet{}, }, @@ -42,7 +42,7 @@ func TestNewIDTokenHintVerifier(t *testing.T) { WithSupportedIDTokenHintSigningAlgorithms("ABC", "DEF"), }, }, - want: &oidc.Verifier{ + want: &IDTokenHintVerifier{ Issuer: tu.ValidIssuer, KeySet: tu.KeySet{}, SupportedSignAlgs: []string{"ABC", "DEF"}, @@ -58,7 +58,7 @@ func TestNewIDTokenHintVerifier(t *testing.T) { } func TestVerifyIDTokenHint(t *testing.T) { - verifier := &oidc.Verifier{ + verifier := &IDTokenHintVerifier{ Issuer: tu.ValidIssuer, MaxAgeIAT: 2 * time.Minute, Offset: time.Second,