diff --git a/HISTORY.md b/HISTORY.md
index 33dc71be1..8738a8aaf 100644
--- a/HISTORY.md
+++ b/HISTORY.md
@@ -1,6 +1,20 @@
 This is a list of breaking changes. As long as `1.0.0` is not released, breaking changes will be addressed as minor version
 bumps (`0.1.0` -> `0.2.0`).
 
+## 0.5.0
+
+Breaking changes:
+
+* `compose.OpenIDConnectExplicit` is now `compose.OpenIDConnectExplicitFactory`
+* `compose.OpenIDConnectImplicit` is now `compose.OpenIDConnectImplicitFactory`
+* `compose.OpenIDConnectHybrid` is now `compose.OpenIDConnectHybridFactory`
+* The token introspection handler is no longer added automatically by `compose.OAuth2*`. Add `compose.OAuth2TokenIntrospectionFactory`
+to your composer if you need token introspection.
+* Session refactor:
+  * The HMACSessionContainer was removed and replaced by `fosite.Session` / `fosite.DefaultSession`. All sessions
+  must now implement this signature. The new session interface allows for better expiration time handling.
+  * The OpenID `DefaultSession` signature changed as well, it is now implementing the `fosite.Session` interface
+
 ## 0.4.0
 
 Breaking changes:
diff --git a/README.md b/README.md
index cb61549fe..e7b39317d 100644
--- a/README.md
+++ b/README.md
@@ -202,20 +202,6 @@ var config = compose.Config {
 
 var oauth2Provider = compose.ComposeAllEnabled(config *Config, storage, secret, privateKey)
 
-// The session will be persisted by the store and made available when e.g. validating tokens or handling token endpoint requests.
-// The default OAuth2 and OpenID Connect handlers require the session to implement a few methods. Apart from that, the 
-// session struct can be anything you want it to be.
-type session struct {
-	UserID string
-	Foobar int
-	
-	// this is used in the OAuth2 handlers. You can set per-session expiry times here, for example.
-	*oauth2Strat.HMACSession
-	
-	// this is used by the OpenID connect handlers. You can set custom id token headers and claims.
-	*oidcStrat.DefaultSession
-}
-
 // The authorize endpoint is usually at "https://mydomain.com/oauth2/auth".
 func authorizeHandlerFunc(rw http.ResponseWriter, req *http.Request) {
 	// This context will be passed to all methods. It doesn't fulfill a real purpose in the standard library but could be used
@@ -247,8 +233,12 @@ func authorizeHandlerFunc(rw http.ResponseWriter, req *http.Request) {
 
 	// Now that the user is authorized, we set up a session. When validating / looking up tokens, we additionally get
 	// the session. You can store anything you want in it.
-	mySessionData := &session{
-		UserID: req.Form.Get("username")
+	
+    // The session will be persisted by the store and made available when e.g. validating tokens or handling token endpoint requests.
+    // The default OAuth2 and OpenID Connect handlers require the session to implement a few methods. Apart from that, the 
+    // session struct can be anything you want it to be.
+	mySessionData := &fosite.DefaultSession{
+		Username: req.Form.Get("username")
 	}
 
 	// It's also wise to check the requested scopes, e.g.:
@@ -273,7 +263,7 @@ func authorizeHandlerFunc(rw http.ResponseWriter, req *http.Request) {
 // The token endpoint is usually at "https://mydomain.com/oauth2/token"
 func tokenHandlerFunc(rw http.ResponseWriter, req *http.Request) {
 	ctx := NewContext()
-	mySessionData := &session{}
+	mySessionData := new(fosite.DefaultSession)
 
 	// This will create an access request object and iterate through the registered TokenEndpointHandlers to validate the request.
 	accessRequest, err := oauth2.NewAccessRequest(ctx, req, mySessionData)
@@ -302,7 +292,7 @@ func tokenHandlerFunc(rw http.ResponseWriter, req *http.Request) {
 
 func someResourceProviderHandlerFunc(rw http.ResponseWriter, req *http.Request) {
 	ctx := NewContext()
-	mySessionData := &session{}
+	mySessionData := new(fosite.DefaultSession)
 	requiredScope := "blogposts.create"
 
 	ar, err := oauth2.IntrospectToken(ctx, fosite.AccessTokenFromRequest(req), mySessionData, requiredScope)
diff --git a/access_request.go b/access_request.go
index 00c56b8b4..810b7de3e 100644
--- a/access_request.go
+++ b/access_request.go
@@ -7,7 +7,7 @@ type AccessRequest struct {
 	Request
 }
 
-func NewAccessRequest(session interface{}) *AccessRequest {
+func NewAccessRequest(session Session) *AccessRequest {
 	r := &AccessRequest{
 		GrantTypes:       Arguments{},
 		HandledGrantType: Arguments{},
diff --git a/access_request_handler.go b/access_request_handler.go
index 13910cecb..76c80331b 100644
--- a/access_request_handler.go
+++ b/access_request_handler.go
@@ -33,7 +33,7 @@ import (
 //   credentials (or assigned other authentication requirements), the
 //   client MUST authenticate with the authorization server as described
 //   in Section 3.2.1.
-func (f *Fosite) NewAccessRequest(ctx context.Context, r *http.Request, session interface{}) (AccessRequester, error) {
+func (f *Fosite) NewAccessRequest(ctx context.Context, r *http.Request, session Session) (AccessRequester, error) {
 	accessRequest := NewAccessRequest(session)
 
 	if r.Method != "POST" {
diff --git a/access_request_handler_test.go b/access_request_handler_test.go
index 4bed190f8..05cae91d3 100644
--- a/access_request_handler_test.go
+++ b/access_request_handler_test.go
@@ -183,7 +183,7 @@ func TestNewAccessRequest(t *testing.T) {
 		c.mock()
 		ctx := NewContext()
 		fosite.TokenEndpointHandlers = c.handlers
-		ar, err := fosite.NewAccessRequest(ctx, r, &struct{}{})
+		ar, err := fosite.NewAccessRequest(ctx, r, new(DefaultSession))
 		assert.True(t, errors.Cause(err) == c.expectErr, "%d\nwant: %s \ngot: %s", k, c.expectErr, err)
 		if err != nil {
 			t.Logf("Error occured: %v", err)
diff --git a/access_response.go b/access_response.go
index 0455f73bc..75b15f732 100644
--- a/access_response.go
+++ b/access_response.go
@@ -23,7 +23,7 @@ func (a *AccessResponse) SetScopes(scopes Arguments) {
 }
 
 func (a *AccessResponse) SetExpiresIn(expiresIn time.Duration) {
-	a.SetExtra("expires_in", strconv.Itoa(int(expiresIn)))
+	a.SetExtra("expires_in", strconv.FormatInt(int64(expiresIn/time.Second), 10))
 }
 
 func (a *AccessResponse) SetExtra(key string, value interface{}) {
diff --git a/authorize_request_test.go b/authorize_request_test.go
index 9c18dcf91..b6704bcb7 100644
--- a/authorize_request_test.go
+++ b/authorize_request_test.go
@@ -96,10 +96,10 @@ func TestAuthorizeRequest(t *testing.T) {
 		assert.Equal(t, c.isRedirValid, c.ar.IsRedirectURIValid(), "%d", k)
 
 		c.ar.GrantScope("foo")
-		c.ar.SetSession(&struct{}{})
+		c.ar.SetSession(&DefaultSession{})
 		c.ar.SetRequestedScopes([]string{"foo"})
 		assert.True(t, c.ar.GetGrantedScopes().Has("foo"))
 		assert.True(t, c.ar.GetRequestedScopes().Has("foo"))
-		assert.Equal(t, &struct{}{}, c.ar.GetSession())
+		assert.Equal(t, &DefaultSession{}, c.ar.GetSession())
 	}
 }
diff --git a/authorize_response_writer.go b/authorize_response_writer.go
index b729bc591..b7182057f 100644
--- a/authorize_response_writer.go
+++ b/authorize_response_writer.go
@@ -8,7 +8,7 @@ import (
 	"golang.org/x/net/context"
 )
 
-func (o *Fosite) NewAuthorizeResponse(ctx context.Context, r *http.Request, ar AuthorizeRequester, session interface{}) (AuthorizeResponder, error) {
+func (o *Fosite) NewAuthorizeResponse(ctx context.Context, r *http.Request, ar AuthorizeRequester, session Session) (AuthorizeResponder, error) {
 	var resp = &AuthorizeResponse{
 		Header:   http.Header{},
 		Query:    url.Values{},
diff --git a/authorize_response_writer_test.go b/authorize_response_writer_test.go
index 62b101a9c..e5024e419 100644
--- a/authorize_response_writer_test.go
+++ b/authorize_response_writer_test.go
@@ -25,7 +25,7 @@ func TestNewAuthorizeResponse(t *testing.T) {
 	duo := &Fosite{
 		AuthorizeEndpointHandlers: AuthorizeEndpointHandlers{handlers[0], handlers[0]},
 	}
-	ar.EXPECT().SetSession(gomock.Eq(struct{}{})).AnyTimes()
+	ar.EXPECT().SetSession(gomock.Eq(new(DefaultSession))).AnyTimes()
 	fooErr := errors.New("foo")
 	for k, c := range []struct {
 		isErr     bool
@@ -66,7 +66,7 @@ func TestNewAuthorizeResponse(t *testing.T) {
 		},
 	} {
 		c.mock()
-		responder, err := oauth2.NewAuthorizeResponse(ctx, &http.Request{}, ar, struct{}{})
+		responder, err := oauth2.NewAuthorizeResponse(ctx, &http.Request{}, ar, new(DefaultSession))
 		assert.Equal(t, c.isErr, err != nil, "%d: %s", k, err)
 		if err != nil {
 			assert.Equal(t, c.expectErr, err, "%d: %s", k, err)
diff --git a/compose/compose.go b/compose/compose.go
index 0dc650bd6..4ab8b3ee2 100644
--- a/compose/compose.go
+++ b/compose/compose.go
@@ -75,8 +75,10 @@ func ComposeAllEnabled(config *Config, storage interface{}, secret []byte, key *
 		OAuth2RefreshTokenGrantFactory,
 		OAuth2ResourceOwnerPasswordCredentialsFactory,
 
-		OpenIDConnectExplicit,
-		OpenIDConnectImplicit,
-		OpenIDConnectHybrid,
+		OpenIDConnectExplicitFactory,
+		OpenIDConnectImplicitFactory,
+		OpenIDConnectHybridFactory,
+
+		OAuth2TokenIntrospectionFactory,
 	)
 }
diff --git a/compose/compose_oauth2.go b/compose/compose_oauth2.go
index 3a45b572a..eed09d598 100644
--- a/compose/compose_oauth2.go
+++ b/compose/compose_oauth2.go
@@ -8,134 +8,68 @@ import (
 // OAuth2AuthorizeExplicitFactory creates an OAuth2 authorize code grant ("authorize explicit flow") handler and registers
 // an access token, refresh token and authorize code validator.
 func OAuth2AuthorizeExplicitFactory(config *Config, storage interface{}, strategy interface{}) interface{} {
-	return &struct {
-		// register the handler
-		*oauth2.AuthorizeExplicitGrantHandler
-
-		// also register the validator for access tokens
-		*oauth2.CoreValidator
-	}{
-		AuthorizeExplicitGrantHandler: &oauth2.AuthorizeExplicitGrantHandler{
-			AccessTokenStrategy:       strategy.(oauth2.AccessTokenStrategy),
-			RefreshTokenStrategy:      strategy.(oauth2.RefreshTokenStrategy),
-			AuthorizeCodeStrategy:     strategy.(oauth2.AuthorizeCodeStrategy),
-			AuthorizeCodeGrantStorage: storage.(oauth2.AuthorizeCodeGrantStorage),
-			AuthCodeLifespan:          config.GetAuthorizeCodeLifespan(),
-			AccessTokenLifespan:       config.GetAccessTokenLifespan(),
-			ScopeStrategy:             fosite.HierarchicScopeStrategy,
-		},
-		CoreValidator: &oauth2.CoreValidator{
-			CoreStrategy:  strategy.(oauth2.CoreStrategy),
-			CoreStorage:   storage.(oauth2.CoreStorage),
-			ScopeStrategy: fosite.HierarchicScopeStrategy,
-		},
+	return &oauth2.AuthorizeExplicitGrantHandler{
+		AccessTokenStrategy:       strategy.(oauth2.AccessTokenStrategy),
+		RefreshTokenStrategy:      strategy.(oauth2.RefreshTokenStrategy),
+		AuthorizeCodeStrategy:     strategy.(oauth2.AuthorizeCodeStrategy),
+		AuthorizeCodeGrantStorage: storage.(oauth2.AuthorizeCodeGrantStorage),
+		AuthCodeLifespan:          config.GetAuthorizeCodeLifespan(),
+		AccessTokenLifespan:       config.GetAccessTokenLifespan(),
+		ScopeStrategy:             fosite.HierarchicScopeStrategy,
 	}
 }
 
 // OAuth2ClientCredentialsGrantFactory creates an OAuth2 client credentials grant handler and registers
 // an access token, refresh token and authorize code validator.
 func OAuth2ClientCredentialsGrantFactory(config *Config, storage interface{}, strategy interface{}) interface{} {
-	return &struct {
-		// register the handler
-		*oauth2.ClientCredentialsGrantHandler
-
-		// also register the validator for access tokens
-		*oauth2.CoreValidator
-	}{
-		ClientCredentialsGrantHandler: &oauth2.ClientCredentialsGrantHandler{
-			HandleHelper: &oauth2.HandleHelper{
-				AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy),
-				AccessTokenStorage:  storage.(oauth2.AccessTokenStorage),
-				AccessTokenLifespan: config.GetAccessTokenLifespan(),
-			},
-			ScopeStrategy: fosite.HierarchicScopeStrategy,
-		},
-		CoreValidator: &oauth2.CoreValidator{
-			CoreStrategy:  strategy.(oauth2.CoreStrategy),
-			CoreStorage:   storage.(oauth2.CoreStorage),
-			ScopeStrategy: fosite.HierarchicScopeStrategy,
+	return &oauth2.ClientCredentialsGrantHandler{
+		HandleHelper: &oauth2.HandleHelper{
+			AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy),
+			AccessTokenStorage:  storage.(oauth2.AccessTokenStorage),
+			AccessTokenLifespan: config.GetAccessTokenLifespan(),
 		},
+		ScopeStrategy: fosite.HierarchicScopeStrategy,
 	}
 }
 
 // OAuth2RefreshTokenGrantFactory creates an OAuth2 refresh grant handler and registers
 // an access token, refresh token and authorize code validator.
 func OAuth2RefreshTokenGrantFactory(config *Config, storage interface{}, strategy interface{}) interface{} {
-	return &struct {
-		// register the handler
-		*oauth2.RefreshTokenGrantHandler
-
-		// also register the validator for access tokens
-		*oauth2.CoreValidator
-	}{
-		RefreshTokenGrantHandler: &oauth2.RefreshTokenGrantHandler{
-			AccessTokenStrategy:      strategy.(oauth2.AccessTokenStrategy),
-			RefreshTokenStrategy:     strategy.(oauth2.RefreshTokenStrategy),
-			RefreshTokenGrantStorage: storage.(oauth2.RefreshTokenGrantStorage),
-			AccessTokenLifespan:      config.GetAccessTokenLifespan(),
-		},
-		CoreValidator: &oauth2.CoreValidator{
-			CoreStrategy:  strategy.(oauth2.CoreStrategy),
-			CoreStorage:   storage.(oauth2.CoreStorage),
-			ScopeStrategy: fosite.HierarchicScopeStrategy,
-		},
+	return &oauth2.RefreshTokenGrantHandler{
+		AccessTokenStrategy:      strategy.(oauth2.AccessTokenStrategy),
+		RefreshTokenStrategy:     strategy.(oauth2.RefreshTokenStrategy),
+		RefreshTokenGrantStorage: storage.(oauth2.RefreshTokenGrantStorage),
+		AccessTokenLifespan:      config.GetAccessTokenLifespan(),
 	}
 }
 
 // OAuth2AuthorizeImplicitFactory creates an OAuth2 implicit grant ("authorize implicit flow") handler and registers
 // an access token, refresh token and authorize code validator.
 func OAuth2AuthorizeImplicitFactory(config *Config, storage interface{}, strategy interface{}) interface{} {
-	return &struct {
-		// register the handler
-		*oauth2.AuthorizeImplicitGrantTypeHandler
-
-		// also register the validator for access tokens
-		*oauth2.CoreValidator
-	}{
-		AuthorizeImplicitGrantTypeHandler: &oauth2.AuthorizeImplicitGrantTypeHandler{
-			AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy),
-			AccessTokenStorage:  storage.(oauth2.AccessTokenStorage),
-			AccessTokenLifespan: config.GetAccessTokenLifespan(),
-			ScopeStrategy:       fosite.HierarchicScopeStrategy,
-		},
-		CoreValidator: &oauth2.CoreValidator{
-			CoreStrategy:  strategy.(oauth2.CoreStrategy),
-			CoreStorage:   storage.(oauth2.CoreStorage),
-			ScopeStrategy: fosite.HierarchicScopeStrategy,
-		},
+	return &oauth2.AuthorizeImplicitGrantTypeHandler{
+		AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy),
+		AccessTokenStorage:  storage.(oauth2.AccessTokenStorage),
+		AccessTokenLifespan: config.GetAccessTokenLifespan(),
+		ScopeStrategy:       fosite.HierarchicScopeStrategy,
 	}
 }
 
 // OAuth2ResourceOwnerPasswordCredentialsFactory creates an OAuth2 resource owner password credentials grant handler and registers
 // an access token, refresh token and authorize code validator.
 func OAuth2ResourceOwnerPasswordCredentialsFactory(config *Config, storage interface{}, strategy interface{}) interface{} {
-	return &struct {
-		// register the handler
-		*oauth2.ResourceOwnerPasswordCredentialsGrantHandler
-
-		// also register the validator for access tokens
-		*oauth2.CoreValidator
-	}{
-		ResourceOwnerPasswordCredentialsGrantHandler: &oauth2.ResourceOwnerPasswordCredentialsGrantHandler{
-			ResourceOwnerPasswordCredentialsGrantStorage: storage.(oauth2.ResourceOwnerPasswordCredentialsGrantStorage),
-			HandleHelper: &oauth2.HandleHelper{
-				AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy),
-				AccessTokenStorage:  storage.(oauth2.AccessTokenStorage),
-				AccessTokenLifespan: config.GetAccessTokenLifespan(),
-			},
-			RefreshTokenStrategy: strategy.(oauth2.RefreshTokenStrategy),
-			ScopeStrategy:        fosite.HierarchicScopeStrategy,
-		},
-		CoreValidator: &oauth2.CoreValidator{
-			CoreStrategy:  strategy.(oauth2.CoreStrategy),
-			CoreStorage:   storage.(oauth2.CoreStorage),
-			ScopeStrategy: fosite.HierarchicScopeStrategy,
+	return &oauth2.ResourceOwnerPasswordCredentialsGrantHandler{
+		ResourceOwnerPasswordCredentialsGrantStorage: storage.(oauth2.ResourceOwnerPasswordCredentialsGrantStorage),
+		HandleHelper: &oauth2.HandleHelper{
+			AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy),
+			AccessTokenStorage:  storage.(oauth2.AccessTokenStorage),
+			AccessTokenLifespan: config.GetAccessTokenLifespan(),
 		},
+		RefreshTokenStrategy: strategy.(oauth2.RefreshTokenStrategy),
+		ScopeStrategy:        fosite.HierarchicScopeStrategy,
 	}
 }
 
-// OAuth2TokenRevocationFactory creates an OAuth2 token revocation handler and registers
-// an access token, refresh token and authorize code validator.
+// OAuth2TokenRevocationFactory creates an OAuth2 token revocation handler.
 func OAuth2TokenRevocationFactory(config *Config, storage interface{}, strategy interface{}) interface{} {
 	return &oauth2.TokenRevocationHandler{
 		TokenRevocationStorage: storage.(oauth2.TokenRevocationStorage),
@@ -143,3 +77,13 @@ func OAuth2TokenRevocationFactory(config *Config, storage interface{}, strategy
 		RefreshTokenStrategy:   strategy.(oauth2.RefreshTokenStrategy),
 	}
 }
+
+// OAuth2TokenIntrospectionFactory creates an OAuth2 token introspection handler and registers
+// an access token and refresh token validator.
+func OAuth2TokenIntrospectionFactory(config *Config, storage interface{}, strategy interface{}) interface{} {
+	return &oauth2.CoreValidator{
+		CoreStrategy:  strategy.(oauth2.CoreStrategy),
+		CoreStorage:   storage.(oauth2.CoreStorage),
+		ScopeStrategy: fosite.HierarchicScopeStrategy,
+	}
+}
diff --git a/compose/compose_openid.go b/compose/compose_openid.go
index 3816d3960..f231f087b 100644
--- a/compose/compose_openid.go
+++ b/compose/compose_openid.go
@@ -6,65 +6,53 @@ import (
 	"github.com/ory-am/fosite/handler/openid"
 )
 
-// OpenIDConnectExplicit creates an OpenID Connect explicit ("authorize code flow") grant handler. You must add this handler
+// OpenIDConnectExplicitFactory creates an OpenID Connect explicit ("authorize code flow") grant handler. You must add this handler
 // *after* you have added an OAuth2 authorize code handler!
-func OpenIDConnectExplicit(config *Config, storage interface{}, strategy interface{}) interface{} {
-	return &struct {
-		*openid.OpenIDConnectExplicitHandler
-	}{
-		OpenIDConnectExplicitHandler: &openid.OpenIDConnectExplicitHandler{
-			OpenIDConnectRequestStorage: storage.(openid.OpenIDConnectRequestStorage),
-			IDTokenHandleHelper: &openid.IDTokenHandleHelper{
-				IDTokenStrategy: strategy.(openid.OpenIDConnectTokenStrategy),
-			},
+func OpenIDConnectExplicitFactory(config *Config, storage interface{}, strategy interface{}) interface{} {
+	return &openid.OpenIDConnectExplicitHandler{
+		OpenIDConnectRequestStorage: storage.(openid.OpenIDConnectRequestStorage),
+		IDTokenHandleHelper: &openid.IDTokenHandleHelper{
+			IDTokenStrategy: strategy.(openid.OpenIDConnectTokenStrategy),
 		},
 	}
 }
 
-// OpenIDConnectImplicit creates an OpenID Connect implicit ("implicit flow") grant handler. You must add this handler
+// OpenIDConnectImplicitFactory creates an OpenID Connect implicit ("implicit flow") grant handler. You must add this handler
 // *after* you have added an OAuth2 authorize implicit handler!
-func OpenIDConnectImplicit(config *Config, storage interface{}, strategy interface{}) interface{} {
-	return &struct {
-		*openid.OpenIDConnectImplicitHandler
-	}{
-		OpenIDConnectImplicitHandler: &openid.OpenIDConnectImplicitHandler{
-			AuthorizeImplicitGrantTypeHandler: &oauth2.AuthorizeImplicitGrantTypeHandler{
-				AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy),
-				AccessTokenStorage:  storage.(oauth2.AccessTokenStorage),
-				AccessTokenLifespan: config.GetAccessTokenLifespan(),
-			},
-			ScopeStrategy: fosite.HierarchicScopeStrategy,
-			IDTokenHandleHelper: &openid.IDTokenHandleHelper{
-				IDTokenStrategy: strategy.(openid.OpenIDConnectTokenStrategy),
-			},
+func OpenIDConnectImplicitFactory(config *Config, storage interface{}, strategy interface{}) interface{} {
+	return &openid.OpenIDConnectImplicitHandler{
+		AuthorizeImplicitGrantTypeHandler: &oauth2.AuthorizeImplicitGrantTypeHandler{
+			AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy),
+			AccessTokenStorage:  storage.(oauth2.AccessTokenStorage),
+			AccessTokenLifespan: config.GetAccessTokenLifespan(),
+		},
+		ScopeStrategy: fosite.HierarchicScopeStrategy,
+		IDTokenHandleHelper: &openid.IDTokenHandleHelper{
+			IDTokenStrategy: strategy.(openid.OpenIDConnectTokenStrategy),
 		},
 	}
 }
 
-// OpenIDConnectHybrid creates an OpenID Connect hybrid grant handler. You must add this handler
+// OpenIDConnectHybridFactory creates an OpenID Connect hybrid grant handler. You must add this handler
 // *after* you have added an OAuth2 authorize code and implicit authorize handler!
-func OpenIDConnectHybrid(config *Config, storage interface{}, strategy interface{}) interface{} {
-	return &struct {
-		*openid.OpenIDConnectHybridHandler
-	}{
-		OpenIDConnectHybridHandler: &openid.OpenIDConnectHybridHandler{
-			AuthorizeExplicitGrantHandler: &oauth2.AuthorizeExplicitGrantHandler{
-				AccessTokenStrategy:       strategy.(oauth2.AccessTokenStrategy),
-				RefreshTokenStrategy:      strategy.(oauth2.RefreshTokenStrategy),
-				AuthorizeCodeStrategy:     strategy.(oauth2.AuthorizeCodeStrategy),
-				AuthorizeCodeGrantStorage: storage.(oauth2.AuthorizeCodeGrantStorage),
-				AuthCodeLifespan:          config.GetAuthorizeCodeLifespan(),
-				AccessTokenLifespan:       config.GetAccessTokenLifespan(),
-			},
-			ScopeStrategy: fosite.HierarchicScopeStrategy,
-			AuthorizeImplicitGrantTypeHandler: &oauth2.AuthorizeImplicitGrantTypeHandler{
-				AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy),
-				AccessTokenStorage:  storage.(oauth2.AccessTokenStorage),
-				AccessTokenLifespan: config.GetAccessTokenLifespan(),
-			},
-			IDTokenHandleHelper: &openid.IDTokenHandleHelper{
-				IDTokenStrategy: strategy.(openid.OpenIDConnectTokenStrategy),
-			},
+func OpenIDConnectHybridFactory(config *Config, storage interface{}, strategy interface{}) interface{} {
+	return &openid.OpenIDConnectHybridHandler{
+		AuthorizeExplicitGrantHandler: &oauth2.AuthorizeExplicitGrantHandler{
+			AccessTokenStrategy:       strategy.(oauth2.AccessTokenStrategy),
+			RefreshTokenStrategy:      strategy.(oauth2.RefreshTokenStrategy),
+			AuthorizeCodeStrategy:     strategy.(oauth2.AuthorizeCodeStrategy),
+			AuthorizeCodeGrantStorage: storage.(oauth2.AuthorizeCodeGrantStorage),
+			AuthCodeLifespan:          config.GetAuthorizeCodeLifespan(),
+			AccessTokenLifespan:       config.GetAccessTokenLifespan(),
+		},
+		ScopeStrategy: fosite.HierarchicScopeStrategy,
+		AuthorizeImplicitGrantTypeHandler: &oauth2.AuthorizeImplicitGrantTypeHandler{
+			AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy),
+			AccessTokenStorage:  storage.(oauth2.AccessTokenStorage),
+			AccessTokenLifespan: config.GetAccessTokenLifespan(),
+		},
+		IDTokenHandleHelper: &openid.IDTokenHandleHelper{
+			IDTokenStrategy: strategy.(openid.OpenIDConnectTokenStrategy),
 		},
 	}
 }
diff --git a/handler/oauth2/flow_authorize_code_auth.go b/handler/oauth2/flow_authorize_code_auth.go
index 6618d157f..96b4149a3 100644
--- a/handler/oauth2/flow_authorize_code_auth.go
+++ b/handler/oauth2/flow_authorize_code_auth.go
@@ -65,6 +65,7 @@ func (c *AuthorizeExplicitGrantHandler) IssueAuthorizeCode(ctx context.Context,
 		return errors.Wrap(fosite.ErrServerError, err.Error())
 	}
 
+	ar.GetSession().SetExpiresAt(fosite.AuthorizeCode, time.Now().Add(c.AuthCodeLifespan))
 	resp.AddQuery("code", code)
 	resp.AddQuery("state", ar.GetState())
 	resp.AddQuery("scope", strings.Join(ar.GetGrantedScopes(), " "))
diff --git a/handler/oauth2/flow_authorize_code_auth_test.go b/handler/oauth2/flow_authorize_code_auth_test.go
index 172036884..357ece4ab 100644
--- a/handler/oauth2/flow_authorize_code_auth_test.go
+++ b/handler/oauth2/flow_authorize_code_auth_test.go
@@ -24,6 +24,7 @@ func TestAuthorizeCode_HandleAuthorizeEndpointRequest(t *testing.T) {
 	areq := fosite.NewAuthorizeRequest()
 	httpreq := &http.Request{Form: url.Values{}}
 
+	areq.Session = new(fosite.DefaultSession)
 	h := AuthorizeExplicitGrantHandler{
 		AuthorizeCodeGrantStorage: store,
 		AuthorizeCodeStrategy:     chgen,
diff --git a/handler/oauth2/flow_authorize_code_token.go b/handler/oauth2/flow_authorize_code_token.go
index 73e36ae18..55546b9b0 100644
--- a/handler/oauth2/flow_authorize_code_token.go
+++ b/handler/oauth2/flow_authorize_code_token.go
@@ -1,12 +1,11 @@
 package oauth2
 
 import (
-	"net/http"
-	"time"
-
 	"github.com/ory-am/fosite"
 	"github.com/pkg/errors"
 	"golang.org/x/net/context"
+	"net/http"
+	"time"
 )
 
 // HandleTokenEndpointRequest implements
@@ -61,6 +60,7 @@ func (c *AuthorizeExplicitGrantHandler) HandleTokenEndpointRequest(ctx context.C
 	// client MUST authenticate with the authorization server as described
 	// in Section 3.2.1.
 	request.SetSession(authorizeRequest.GetSession())
+	request.GetSession().SetExpiresAt(fosite.AccessToken, time.Now().Add(c.AccessTokenLifespan))
 	return nil
 }
 
@@ -103,7 +103,7 @@ func (c *AuthorizeExplicitGrantHandler) PopulateTokenEndpointResponse(ctx contex
 
 	responder.SetAccessToken(access)
 	responder.SetTokenType("bearer")
-	responder.SetExpiresIn(c.AccessTokenLifespan / time.Second)
+	responder.SetExpiresIn(getExpiresIn(requester, fosite.AccessToken, c.AccessTokenLifespan, time.Now()))
 	responder.SetScopes(requester.GetGrantedScopes())
 	if refresh != "" {
 		responder.SetExtra("refresh_token", refresh)
diff --git a/handler/oauth2/flow_authorize_code_token_test.go b/handler/oauth2/flow_authorize_code_token_test.go
index e81e02627..e75c339c5 100644
--- a/handler/oauth2/flow_authorize_code_token_test.go
+++ b/handler/oauth2/flow_authorize_code_token_test.go
@@ -23,9 +23,10 @@ func TestAuthorizeCode_PopulateTokenEndpointResponse(t *testing.T) {
 	//mockcl := internal.NewMockClient(ctrl)
 	defer ctrl.Finish()
 
-	areq := fosite.NewAccessRequest(nil)
+	areq := fosite.NewAccessRequest(new(fosite.DefaultSession))
 	httpreq := &http.Request{PostForm: url.Values{}}
 	authreq := fosite.NewAuthorizeRequest()
+	areq.Session = new(fosite.DefaultSession)
 
 	h := AuthorizeExplicitGrantHandler{
 		AuthorizeCodeGrantStorage: store,
@@ -55,14 +56,14 @@ func TestAuthorizeCode_PopulateTokenEndpointResponse(t *testing.T) {
 				}
 				httpreq.PostForm.Add("code", "authcode")
 				auch.EXPECT().AuthorizeCodeSignature("authcode").AnyTimes().Return("authsig")
-				store.EXPECT().GetAuthorizeCodeSession(nil, "authsig", nil).Return(nil, fosite.ErrNotFound)
+				store.EXPECT().GetAuthorizeCodeSession(nil, "authsig", gomock.Any()).Return(nil, fosite.ErrNotFound)
 			},
 			expectErr: fosite.ErrServerError,
 		},
 		{
 			description: "should fail because validation failed",
 			setup: func() {
-				store.EXPECT().GetAuthorizeCodeSession(nil, "authsig", nil).AnyTimes().Return(authreq, nil)
+				store.EXPECT().GetAuthorizeCodeSession(nil, "authsig", gomock.Any()).AnyTimes().Return(authreq, nil)
 				auch.EXPECT().ValidateAuthorizeCode(nil, areq, "authcode").Return(errors.New(""))
 			},
 			expectErr: fosite.ErrInvalidRequest,
@@ -122,6 +123,8 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) {
 	authreq := fosite.NewAuthorizeRequest()
 	areq := fosite.NewAccessRequest(nil)
 	httpreq := &http.Request{PostForm: url.Values{}}
+	areq.Session = new(fosite.DefaultSession)
+	authreq.Session = new(fosite.DefaultSession)
 
 	h := AuthorizeExplicitGrantHandler{
 		AuthorizeCodeGrantStorage: store,
@@ -146,14 +149,14 @@ func TestAuthorizeCode_HandleTokenEndpointRequest(t *testing.T) {
 				areq.GrantTypes = fosite.Arguments{"authorization_code"} // grant_type REQUIRED. Value MUST be set to "authorization_code".
 				httpreq.PostForm = url.Values{"code": {"foo.bar"}}
 				ach.EXPECT().AuthorizeCodeSignature("foo.bar").AnyTimes().Return("bar")
-				store.EXPECT().GetAuthorizeCodeSession(nil, "bar", nil).Return(nil, fosite.ErrNotFound)
+				store.EXPECT().GetAuthorizeCodeSession(nil, "bar", gomock.Any()).Return(nil, fosite.ErrNotFound)
 			},
 			expectErr: fosite.ErrInvalidRequest,
 		},
 		{
 			description: "should fail because authcode validation failed",
 			setup: func() {
-				store.EXPECT().GetAuthorizeCodeSession(nil, "bar", nil).AnyTimes().Return(authreq, nil)
+				store.EXPECT().GetAuthorizeCodeSession(nil, "bar", gomock.Any()).AnyTimes().Return(authreq, nil)
 				ach.EXPECT().ValidateAuthorizeCode(nil, areq, "foo.bar").Return(errors.New(""))
 			},
 			expectErr: fosite.ErrInvalidRequest,
diff --git a/handler/oauth2/flow_authorize_implicit.go b/handler/oauth2/flow_authorize_implicit.go
index b3dfd4039..d602c8e08 100644
--- a/handler/oauth2/flow_authorize_implicit.go
+++ b/handler/oauth2/flow_authorize_implicit.go
@@ -2,7 +2,6 @@ package oauth2
 
 import (
 	"net/http"
-	"strconv"
 	"strings"
 	"time"
 
@@ -11,6 +10,7 @@ import (
 	"github.com/ory-am/fosite"
 	"github.com/pkg/errors"
 	"golang.org/x/net/context"
+	"strconv"
 )
 
 // AuthorizeImplicitGrantTypeHandler is a response handler for the Authorize Code grant using the implicit grant type
@@ -63,8 +63,9 @@ func (c *AuthorizeImplicitGrantTypeHandler) IssueImplicitAccessToken(ctx context
 		return errors.Wrap(fosite.ErrServerError, err.Error())
 	}
 
+	ar.GetSession().SetExpiresAt(fosite.AccessToken, time.Now().Add(c.AccessTokenLifespan))
 	resp.AddFragment("access_token", token)
-	resp.AddFragment("expires_in", strconv.Itoa(int(c.AccessTokenLifespan/time.Second)))
+	resp.AddFragment("expires_in", strconv.FormatInt(int64(getExpiresIn(ar, fosite.AccessToken, c.AccessTokenLifespan, time.Now())/time.Second), 10))
 	resp.AddFragment("token_type", "bearer")
 	resp.AddFragment("state", ar.GetState())
 	resp.AddFragment("scope", strings.Join(ar.GetGrantedScopes(), " "))
diff --git a/handler/oauth2/flow_authorize_implicit_test.go b/handler/oauth2/flow_authorize_implicit_test.go
index 01db058cd..5b82a9287 100644
--- a/handler/oauth2/flow_authorize_implicit_test.go
+++ b/handler/oauth2/flow_authorize_implicit_test.go
@@ -3,7 +3,6 @@ package oauth2
 import (
 	"net/http"
 	"net/url"
-	"strconv"
 	"testing"
 	"time"
 
@@ -23,6 +22,7 @@ func TestAuthorizeImplicit_EndpointHandler(t *testing.T) {
 
 	areq := fosite.NewAuthorizeRequest()
 	httpreq := &http.Request{Form: url.Values{}}
+	areq.Session = new(fosite.DefaultSession)
 
 	h := AuthorizeImplicitGrantTypeHandler{
 		AccessTokenStorage:  store,
@@ -70,7 +70,7 @@ func TestAuthorizeImplicit_EndpointHandler(t *testing.T) {
 				store.EXPECT().CreateAccessTokenSession(nil, "ats", areq).AnyTimes().Return(nil)
 
 				aresp.EXPECT().AddFragment("access_token", "access.ats")
-				aresp.EXPECT().AddFragment("expires_in", strconv.Itoa(int(h.AccessTokenLifespan/time.Second)))
+				aresp.EXPECT().AddFragment("expires_in", gomock.Any())
 				aresp.EXPECT().AddFragment("token_type", "bearer")
 				aresp.EXPECT().AddFragment("state", "state")
 				aresp.EXPECT().AddFragment("scope", "scope")
diff --git a/handler/oauth2/flow_client_credentials.go b/handler/oauth2/flow_client_credentials.go
index 32821791c..ba2e08fa2 100644
--- a/handler/oauth2/flow_client_credentials.go
+++ b/handler/oauth2/flow_client_credentials.go
@@ -8,6 +8,7 @@ import (
 	"github.com/ory-am/fosite"
 	"github.com/pkg/errors"
 	"golang.org/x/net/context"
+	"time"
 )
 
 type ClientCredentialsGrantHandler struct {
@@ -38,6 +39,7 @@ func (c *ClientCredentialsGrantHandler) HandleTokenEndpointRequest(_ context.Con
 	}
 	// if the client is not public, he has already been authenticated by the access request handler.
 
+	request.GetSession().SetExpiresAt(fosite.AccessToken, time.Now().Add(c.AccessTokenLifespan))
 	return nil
 }
 
diff --git a/handler/oauth2/flow_client_credentials_test.go b/handler/oauth2/flow_client_credentials_test.go
index 2fc63189f..ffcafd47a 100644
--- a/handler/oauth2/flow_client_credentials_test.go
+++ b/handler/oauth2/flow_client_credentials_test.go
@@ -43,6 +43,7 @@ func TestClientCredentials_HandleTokenEndpointRequest(t *testing.T) {
 		{
 			description: "should pass",
 			mock: func() {
+				areq.EXPECT().GetSession().Return(new(fosite.DefaultSession))
 				areq.EXPECT().GetGrantTypes().Return(fosite.Arguments{"client_credentials"})
 				areq.EXPECT().GetRequestedScopes().Return([]string{"foo", "bar", "baz.bar"})
 				areq.EXPECT().GetClient().Return(&fosite.DefaultClient{
@@ -63,7 +64,7 @@ func TestClientCredentials_PopulateTokenEndpointResponse(t *testing.T) {
 	ctrl := gomock.NewController(t)
 	store := internal.NewMockClientCredentialsGrantStorage(ctrl)
 	chgen := internal.NewMockAccessTokenStrategy(ctrl)
-	areq := fosite.NewAccessRequest(nil)
+	areq := fosite.NewAccessRequest(new(fosite.DefaultSession))
 	aresp := fosite.NewAccessResponse()
 	defer ctrl.Finish()
 
@@ -100,7 +101,7 @@ func TestClientCredentials_PopulateTokenEndpointResponse(t *testing.T) {
 			description: "should pass",
 			mock: func() {
 				areq.GrantTypes = fosite.Arguments{"client_credentials"}
-
+				areq.Session = &fosite.DefaultSession{}
 				areq.Client = &fosite.DefaultClient{GrantTypes: fosite.Arguments{"client_credentials"}}
 				chgen.EXPECT().GenerateAccessToken(nil, areq).Return("tokenfoo.bar", "bar", nil)
 				store.EXPECT().CreateAccessTokenSession(nil, "bar", areq).Return(nil)
diff --git a/handler/oauth2/flow_refresh.go b/handler/oauth2/flow_refresh.go
index 08b0ef836..d14376319 100644
--- a/handler/oauth2/flow_refresh.go
+++ b/handler/oauth2/flow_refresh.go
@@ -63,6 +63,7 @@ func (c *RefreshTokenGrantHandler) HandleTokenEndpointRequest(ctx context.Contex
 		request.GrantScope(scope)
 	}
 
+	request.GetSession().SetExpiresAt(fosite.AccessToken, time.Now().Add(c.AccessTokenLifespan))
 	return nil
 }
 
@@ -89,7 +90,7 @@ func (c *RefreshTokenGrantHandler) PopulateTokenEndpointResponse(ctx context.Con
 
 	responder.SetAccessToken(accessToken)
 	responder.SetTokenType("bearer")
-	responder.SetExpiresIn(c.AccessTokenLifespan / time.Second)
+	responder.SetExpiresIn(getExpiresIn(requester, fosite.AccessToken, c.AccessTokenLifespan, time.Now()))
 	responder.SetScopes(requester.GetGrantedScopes())
 	responder.SetExtra("refresh_token", refreshToken)
 	return nil
diff --git a/handler/oauth2/flow_refresh_test.go b/handler/oauth2/flow_refresh_test.go
index d9276133d..5378f2722 100644
--- a/handler/oauth2/flow_refresh_test.go
+++ b/handler/oauth2/flow_refresh_test.go
@@ -20,7 +20,7 @@ func TestRefreshFlow_HandleTokenEndpointRequest(t *testing.T) {
 	defer ctrl.Finish()
 
 	areq := fosite.NewAccessRequest(nil)
-	sess := struct{ Subject string }{Subject: "othersub"}
+	sess := &fosite.DefaultSession{Subject: "othersub"}
 	httpreq := &http.Request{PostForm: url.Values{}}
 
 	h := RefreshTokenGrantHandler{
@@ -166,6 +166,7 @@ func TestRefreshFlow_PopulateTokenEndpointResponse(t *testing.T) {
 		{
 			description: "should pass",
 			setup: func() {
+				areq.Session = &fosite.DefaultSession{}
 				store.EXPECT().PersistRefreshTokenGrantSession(nil, "reftokensig", "atsig", "resig", areq).AnyTimes().Return(nil)
 
 				aresp.EXPECT().SetAccessToken("access.atsig")
diff --git a/handler/oauth2/flow_resource_owner_test.go b/handler/oauth2/flow_resource_owner_test.go
index 350b65c21..083f041ac 100644
--- a/handler/oauth2/flow_resource_owner_test.go
+++ b/handler/oauth2/flow_resource_owner_test.go
@@ -111,6 +111,7 @@ func TestResourceOwnerFlow_PopulateTokenEndpointResponse(t *testing.T) {
 		{
 			description: "should pass",
 			setup: func() {
+				areq.Session = &fosite.DefaultSession{}
 				areq.GrantTypes = fosite.Arguments{"password"}
 				chgen.EXPECT().GenerateAccessToken(nil, areq).Return(mockAT, "bar", nil)
 				store.EXPECT().CreateAccessTokenSession(nil, "bar", areq).Return(nil)
diff --git a/handler/oauth2/helper.go b/handler/oauth2/helper.go
index 9c126e1f7..e94e23fb1 100644
--- a/handler/oauth2/helper.go
+++ b/handler/oauth2/helper.go
@@ -24,7 +24,14 @@ func (h *HandleHelper) IssueAccessToken(ctx context.Context, req *http.Request,
 
 	responder.SetAccessToken(token)
 	responder.SetTokenType("bearer")
-	responder.SetExpiresIn(h.AccessTokenLifespan / time.Second)
+	responder.SetExpiresIn(getExpiresIn(requester, fosite.AccessToken, h.AccessTokenLifespan, time.Now()))
 	responder.SetScopes(requester.GetGrantedScopes())
 	return nil
 }
+
+func getExpiresIn(r fosite.Requester, key fosite.TokenType, defaultLifespan time.Duration, now time.Time) time.Duration {
+	if r.GetSession().GetExpiresAt(key).IsZero() {
+		return defaultLifespan
+	}
+	return time.Duration(r.GetSession().GetExpiresAt(key).UnixNano() - now.UnixNano())
+}
diff --git a/handler/oauth2/helper_test.go b/handler/oauth2/helper_test.go
index 20dcad215..67f5945b9 100644
--- a/handler/oauth2/helper_test.go
+++ b/handler/oauth2/helper_test.go
@@ -13,6 +13,16 @@ import (
 	"github.com/stretchr/testify/require"
 )
 
+func TestGetExpiresIn(t *testing.T) {
+	now := time.Now()
+	r := fosite.NewAccessRequest(&fosite.DefaultSession{
+		ExpiresAt: map[fosite.TokenType]time.Time{
+			fosite.AccessToken: now.Add(time.Hour),
+		},
+	})
+	assert.Equal(t, time.Hour, getExpiresIn(r, fosite.AccessToken, time.Millisecond, now))
+}
+
 func TestIssueAccessToken(t *testing.T) {
 	ctrl := gomock.NewController(t)
 	areq := &fosite.AccessRequest{}
@@ -28,6 +38,7 @@ func TestIssueAccessToken(t *testing.T) {
 		AccessTokenLifespan: time.Hour,
 	}
 
+	areq.Session = &fosite.DefaultSession{}
 	for k, c := range []struct {
 		mock func()
 		err  error
diff --git a/handler/oauth2/storage.go b/handler/oauth2/storage.go
index 49e2c677b..240272531 100644
--- a/handler/oauth2/storage.go
+++ b/handler/oauth2/storage.go
@@ -14,7 +14,7 @@ type CoreStorage interface {
 type AuthorizeCodeStorage interface {
 	CreateAuthorizeCodeSession(ctx context.Context, code string, request fosite.Requester) (err error)
 
-	GetAuthorizeCodeSession(ctx context.Context, code string, session interface{}) (request fosite.Requester, err error)
+	GetAuthorizeCodeSession(ctx context.Context, code string, session fosite.Session) (request fosite.Requester, err error)
 
 	DeleteAuthorizeCodeSession(ctx context.Context, code string) (err error)
 }
@@ -22,7 +22,7 @@ type AuthorizeCodeStorage interface {
 type AccessTokenStorage interface {
 	CreateAccessTokenSession(ctx context.Context, signature string, request fosite.Requester) (err error)
 
-	GetAccessTokenSession(ctx context.Context, signature string, session interface{}) (request fosite.Requester, err error)
+	GetAccessTokenSession(ctx context.Context, signature string, session fosite.Session) (request fosite.Requester, err error)
 
 	DeleteAccessTokenSession(ctx context.Context, signature string) (err error)
 }
@@ -30,7 +30,7 @@ type AccessTokenStorage interface {
 type RefreshTokenStorage interface {
 	CreateRefreshTokenSession(ctx context.Context, signature string, request fosite.Requester) (err error)
 
-	GetRefreshTokenSession(ctx context.Context, signature string, session interface{}) (request fosite.Requester, err error)
+	GetRefreshTokenSession(ctx context.Context, signature string, session fosite.Session) (request fosite.Requester, err error)
 
 	DeleteRefreshTokenSession(ctx context.Context, signature string) (err error)
 }
diff --git a/handler/oauth2/strategy_hmacsha.go b/handler/oauth2/strategy_hmacsha.go
index 3a3c0e0c9..c1f7ab10b 100644
--- a/handler/oauth2/strategy_hmacsha.go
+++ b/handler/oauth2/strategy_hmacsha.go
@@ -1,7 +1,6 @@
 package oauth2
 
 import (
-	"reflect"
 	"time"
 
 	"fmt"
@@ -32,10 +31,12 @@ func (h HMACSHAStrategy) GenerateAccessToken(_ context.Context, _ fosite.Request
 }
 
 func (h HMACSHAStrategy) ValidateAccessToken(_ context.Context, r fosite.Requester, token string) (err error) {
-	if session, ok := r.GetSession().(HMACSessionContainer); !ok {
-		return errors.Wrap(fosite.ErrMisconfiguration, fmt.Sprintf("Session must be of type HMACSessionContainer, got: %s", reflect.TypeOf(r.GetSession())))
-	} else if session.AccessTokenExpiresAt(r.GetRequestedAt().Add(h.AccessTokenLifespan)).Before(time.Now()) {
-		return errors.Wrap(fosite.ErrTokenExpired, fmt.Sprintf("Access token expired at %s", session.AccessTokenExpiresAt(r.GetRequestedAt().Add(h.AccessTokenLifespan))))
+	var exp = r.GetSession().GetExpiresAt(fosite.AccessToken)
+	if exp.IsZero() && r.GetRequestedAt().Add(h.AccessTokenLifespan).Before(time.Now()) {
+		return errors.Wrap(fosite.ErrTokenExpired, fmt.Sprintf("Access token expired at %s", r.GetRequestedAt().Add(h.AccessTokenLifespan)))
+	}
+	if !exp.IsZero() && exp.Before(time.Now()) {
+		return errors.Wrap(fosite.ErrTokenExpired, fmt.Sprintf("Access token expired at %s", exp))
 	}
 	return h.Enigma.Validate(token)
 }
@@ -53,10 +54,12 @@ func (h HMACSHAStrategy) GenerateAuthorizeCode(_ context.Context, _ fosite.Reque
 }
 
 func (h HMACSHAStrategy) ValidateAuthorizeCode(_ context.Context, r fosite.Requester, token string) (err error) {
-	if session, ok := r.GetSession().(HMACSessionContainer); !ok {
-		return errors.Wrap(fosite.ErrMisconfiguration, fmt.Sprintf("Session must be of type HMACSessionContainer, got: %s", reflect.TypeOf(r.GetSession())))
-	} else if session.AuthorizeCodeExpiresAt(r.GetRequestedAt().Add(h.AuthorizeCodeLifespan)).Before(time.Now()) {
-		return errors.Wrap(fosite.ErrTokenExpired, fmt.Sprintf("Authorize code expired at %s", session.AuthorizeCodeExpiresAt(r.GetRequestedAt().Add(h.AccessTokenLifespan))))
+	var exp = r.GetSession().GetExpiresAt(fosite.AuthorizeCode)
+	if exp.IsZero() && r.GetRequestedAt().Add(h.AuthorizeCodeLifespan).Before(time.Now()) {
+		return errors.Wrap(fosite.ErrTokenExpired, fmt.Sprintf("Authorize code expired at %s", r.GetRequestedAt().Add(h.AuthorizeCodeLifespan)))
+	}
+	if !exp.IsZero() && exp.Before(time.Now()) {
+		return errors.Wrap(fosite.ErrTokenExpired, fmt.Sprintf("Authorize code expired at %s", exp))
 	}
 
 	return h.Enigma.Validate(token)
diff --git a/handler/oauth2/strategy_hmacsha_session.go b/handler/oauth2/strategy_hmacsha_session.go
deleted file mode 100644
index ded6ba219..000000000
--- a/handler/oauth2/strategy_hmacsha_session.go
+++ /dev/null
@@ -1,37 +0,0 @@
-package oauth2
-
-import (
-	"time"
-)
-
-type HMACSessionContainer interface {
-	// AccessTokenExpiresAt returns the access token's expiry.
-	AccessTokenExpiresAt(fallback time.Time) time.Time
-
-	// AccessTokenExpiresAt returns the authorize code's expiry.
-	AuthorizeCodeExpiresAt(fallback time.Time) time.Time
-}
-
-// HMACSession Container for the HMAC session.
-type HMACSession struct {
-	AccessTokenExpiry   time.Time
-	AuthorizeCodeExpiry time.Time
-}
-
-func (s *HMACSession) AccessTokenExpiresAt(fallback time.Time) time.Time {
-	if s == nil {
-		return fallback
-	} else if s.AccessTokenExpiry.IsZero() {
-		return fallback
-	}
-	return s.AccessTokenExpiry
-}
-
-func (s *HMACSession) AuthorizeCodeExpiresAt(fallback time.Time) time.Time {
-	if s == nil {
-		return fallback
-	} else if s.AuthorizeCodeExpiry.IsZero() {
-		return fallback
-	}
-	return s.AuthorizeCodeExpiry
-}
diff --git a/handler/oauth2/strategy_hmacsha_test.go b/handler/oauth2/strategy_hmacsha_test.go
index 64080a75a..7bcd1fffe 100644
--- a/handler/oauth2/strategy_hmacsha_test.go
+++ b/handler/oauth2/strategy_hmacsha_test.go
@@ -18,9 +18,11 @@ var hmacExpiredCase = fosite.Request{
 	Client: &fosite.DefaultClient{
 		Secret: []byte("foobarfoobarfoobarfoobar"),
 	},
-	Session: &HMACSession{
-		AccessTokenExpiry:   time.Now().Add(-time.Hour),
-		AuthorizeCodeExpiry: time.Now().Add(-time.Hour),
+	Session: &fosite.DefaultSession{
+		ExpiresAt: map[fosite.TokenType]time.Time{
+			fosite.AccessToken:   time.Now().Add(-time.Hour),
+			fosite.AuthorizeCode: time.Now().Add(-time.Hour),
+		},
 	},
 }
 
@@ -28,9 +30,11 @@ var hmacValidCase = fosite.Request{
 	Client: &fosite.DefaultClient{
 		Secret: []byte("foobarfoobarfoobarfoobar"),
 	},
-	Session: &HMACSession{
-		AccessTokenExpiry:   time.Now().Add(time.Hour),
-		AuthorizeCodeExpiry: time.Now().Add(time.Hour),
+	Session: &fosite.DefaultSession{
+		ExpiresAt: map[fosite.TokenType]time.Time{
+			fosite.AccessToken:   time.Now().Add(time.Hour),
+			fosite.AuthorizeCode: time.Now().Add(time.Hour),
+		},
 	},
 }
 
@@ -75,7 +79,7 @@ func TestHMACRefreshToken(t *testing.T) {
 }
 
 func TestHMACAuthorizeCode(t *testing.T) {
-	for _, c := range []struct {
+	for k, c := range []struct {
 		r    fosite.Request
 		pass bool
 	}{
@@ -94,11 +98,11 @@ func TestHMACAuthorizeCode(t *testing.T) {
 
 		err = s.ValidateAuthorizeCode(nil, &c.r, token)
 		if c.pass {
-			assert.Nil(t, err, "%s", err)
+			assert.Nil(t, err, "%d: %s", k, err)
 			validate := s.Enigma.Signature(token)
 			assert.Equal(t, signature, validate)
 		} else {
-			assert.NotNil(t, err, "%s", err)
+			assert.NotNil(t, err, "%d: %s", k, err)
 		}
 	}
 }
diff --git a/handler/oauth2/strategy_jwt_session.go b/handler/oauth2/strategy_jwt_session.go
index c4c35aec8..ce485c268 100644
--- a/handler/oauth2/strategy_jwt_session.go
+++ b/handler/oauth2/strategy_jwt_session.go
@@ -1,7 +1,9 @@
 package oauth2
 
 import (
+	"github.com/ory-am/fosite"
 	"github.com/ory-am/fosite/token/jwt"
+	"time"
 )
 
 type JWTSessionContainer interface {
@@ -10,12 +12,17 @@ type JWTSessionContainer interface {
 
 	// GetJWTHeader returns the header.
 	GetJWTHeader() *jwt.Headers
+
+	fosite.Session
 }
 
 // JWTSession Container for the JWT session.
 type JWTSession struct {
 	JWTClaims *jwt.JWTClaims
 	JWTHeader *jwt.Headers
+	ExpiresAt map[fosite.TokenType]time.Time
+	Username  string
+	Subject   string
 }
 
 func (j *JWTSession) GetJWTClaims() *jwt.JWTClaims {
@@ -31,3 +38,36 @@ func (j *JWTSession) GetJWTHeader() *jwt.Headers {
 	}
 	return j.JWTHeader
 }
+
+func (s *JWTSession) SetExpiresAt(key fosite.TokenType, exp time.Time) {
+	if s.ExpiresAt == nil {
+		s.ExpiresAt = make(map[fosite.TokenType]time.Time)
+	}
+	s.ExpiresAt[key] = exp
+}
+
+func (s *JWTSession) GetExpiresAt(key fosite.TokenType) time.Time {
+	if s.ExpiresAt == nil {
+		s.ExpiresAt = make(map[fosite.TokenType]time.Time)
+	}
+
+	if _, ok := s.ExpiresAt[key]; !ok {
+		return time.Time{}
+	}
+	return s.ExpiresAt[key]
+}
+
+func (s *JWTSession) GetUsername() string {
+	if s == nil {
+		return ""
+	}
+	return s.Username
+}
+
+func (s *JWTSession) GetSubject() string {
+	if s == nil {
+		return ""
+	}
+
+	return s.Subject
+}
diff --git a/handler/openid/flow_hybrid.go b/handler/openid/flow_hybrid.go
index 742333ca6..2a880d6de 100644
--- a/handler/openid/flow_hybrid.go
+++ b/handler/openid/flow_hybrid.go
@@ -19,7 +19,7 @@ type OpenIDConnectHybridHandler struct {
 	IDTokenHandleHelper               *IDTokenHandleHelper
 	ScopeStrategy                     fosite.ScopeStrategy
 
-	Enigma *jwt.RS256JWTStrategy
+	Enigma                            *jwt.RS256JWTStrategy
 }
 
 func (c *OpenIDConnectHybridHandler) HandleAuthorizeEndpointRequest(ctx context.Context, req *http.Request, ar fosite.AuthorizeRequester, resp fosite.AuthorizeResponder) error {
@@ -69,7 +69,7 @@ func (c *OpenIDConnectHybridHandler) HandleAuthorizeEndpointRequest(ctx context.
 		if err != nil {
 			return err
 		}
-		claims.CodeHash = []byte(base64.URLEncoding.EncodeToString([]byte(hash[:c.Enigma.GetSigningMethodLength()/2])))
+		claims.CodeHash = []byte(base64.URLEncoding.EncodeToString([]byte(hash[:c.Enigma.GetSigningMethodLength() / 2])))
 	}
 
 	if ar.GetResponseTypes().Has("token") {
@@ -84,7 +84,7 @@ func (c *OpenIDConnectHybridHandler) HandleAuthorizeEndpointRequest(ctx context.
 		if err != nil {
 			return err
 		}
-		claims.AccessTokenHash = []byte(base64.URLEncoding.EncodeToString([]byte(hash[:c.Enigma.GetSigningMethodLength()/2])))
+		claims.AccessTokenHash = []byte(base64.URLEncoding.EncodeToString([]byte(hash[:c.Enigma.GetSigningMethodLength() / 2])))
 	}
 
 	if !ar.GetGrantedScopes().Has("openid") {
diff --git a/handler/openid/flow_hybrid_test.go b/handler/openid/flow_hybrid_test.go
index fbcd72a64..db667e6f3 100644
--- a/handler/openid/flow_hybrid_test.go
+++ b/handler/openid/flow_hybrid_test.go
@@ -32,7 +32,7 @@ var hmacStrategy = &oauth2.HMACSHAStrategy{
 type defaultSession struct {
 	Claims  *jwt.IDTokenClaims
 	Headers *jwt.Headers
-	*oauth2.HMACSession
+	*fosite.DefaultSession
 }
 
 func (s *defaultSession) IDTokenHeaders() *jwt.Headers {
@@ -116,8 +116,8 @@ func TestHybrid_HandleAuthorizeEndpointRequest(t *testing.T) {
 					Claims: &jwt.IDTokenClaims{
 						Subject: "peter",
 					},
-					Headers:     &jwt.Headers{},
-					HMACSession: &oauth2.HMACSession{},
+					Headers:        &jwt.Headers{},
+					DefaultSession: new(fosite.DefaultSession),
 				}
 			},
 			expectErr: fosite.ErrInvalidGrant,
diff --git a/handler/openid/flow_implicit.go b/handler/openid/flow_implicit.go
index 02441460e..f618b2861 100644
--- a/handler/openid/flow_implicit.go
+++ b/handler/openid/flow_implicit.go
@@ -16,9 +16,9 @@ import (
 type OpenIDConnectImplicitHandler struct {
 	AuthorizeImplicitGrantTypeHandler *oauth2.AuthorizeImplicitGrantTypeHandler
 	*IDTokenHandleHelper
-	ScopeStrategy fosite.ScopeStrategy
+	ScopeStrategy                     fosite.ScopeStrategy
 
-	RS256JWTStrategy *jwt.RS256JWTStrategy
+	RS256JWTStrategy                  *jwt.RS256JWTStrategy
 }
 
 func (c *OpenIDConnectImplicitHandler) HandleAuthorizeEndpointRequest(ctx context.Context, req *http.Request, ar fosite.AuthorizeRequester, resp fosite.AuthorizeResponder) error {
@@ -63,7 +63,7 @@ func (c *OpenIDConnectImplicitHandler) HandleAuthorizeEndpointRequest(ctx contex
 			return err
 		}
 
-		claims.AccessTokenHash = []byte(base64.URLEncoding.EncodeToString([]byte(hash[:c.RS256JWTStrategy.GetSigningMethodLength()/2])))
+		claims.AccessTokenHash = []byte(base64.URLEncoding.EncodeToString([]byte(hash[:c.RS256JWTStrategy.GetSigningMethodLength() / 2])))
 	} else {
 		resp.AddFragment("state", ar.GetState())
 	}
diff --git a/handler/openid/flow_implicit_test.go b/handler/openid/flow_implicit_test.go
index a26e8285d..e3e5406bf 100644
--- a/handler/openid/flow_implicit_test.go
+++ b/handler/openid/flow_implicit_test.go
@@ -22,6 +22,7 @@ func TestImplicit_HandleAuthorizeEndpointRequest(t *testing.T) {
 	aresp := fosite.NewAuthorizeResponse()
 	areq := fosite.NewAuthorizeRequest()
 	httpreq := &http.Request{Form: url.Values{}}
+	areq.Session = new(fosite.DefaultSession)
 
 	h := OpenIDConnectImplicitHandler{
 		AuthorizeImplicitGrantTypeHandler: &oauth2.AuthorizeImplicitGrantTypeHandler{
@@ -110,7 +111,7 @@ func TestImplicit_HandleAuthorizeEndpointRequest(t *testing.T) {
 					Claims: &jwt.IDTokenClaims{
 						Subject: "peter",
 					},
-					Headers: &jwt.Headers{},
+					Headers:        &jwt.Headers{},
 				}
 				areq.Form.Add("nonce", "some-random-foo-nonce-wow")
 			},
diff --git a/handler/openid/strategy_jwt.go b/handler/openid/strategy_jwt.go
index b69416c37..a2ef76564 100644
--- a/handler/openid/strategy_jwt.go
+++ b/handler/openid/strategy_jwt.go
@@ -16,12 +16,57 @@ const defaultExpiryTime = time.Hour
 type Session interface {
 	IDTokenClaims() *jwt.IDTokenClaims
 	IDTokenHeaders() *jwt.Headers
+
+	fosite.Session
 }
 
 // IDTokenSession is a session container for the id token
 type DefaultSession struct {
-	Claims  *jwt.IDTokenClaims
-	Headers *jwt.Headers
+	Claims    *jwt.IDTokenClaims
+	Headers   *jwt.Headers
+	ExpiresAt map[fosite.TokenType]time.Time
+	Username  string
+	Subject   string
+}
+
+func NewDefaultSession() *DefaultSession {
+	return &DefaultSession{
+		Claims:         &jwt.IDTokenClaims{},
+		Headers:        &jwt.Headers{},
+	}
+}
+
+func (s *DefaultSession) SetExpiresAt(key fosite.TokenType, exp time.Time) {
+	if s.ExpiresAt == nil {
+		s.ExpiresAt = make(map[fosite.TokenType]time.Time)
+	}
+	s.ExpiresAt[key] = exp
+}
+
+func (s *DefaultSession) GetExpiresAt(key fosite.TokenType) time.Time {
+	if s.ExpiresAt == nil {
+		s.ExpiresAt = make(map[fosite.TokenType]time.Time)
+	}
+
+	if _, ok := s.ExpiresAt[key]; !ok {
+		return time.Time{}
+	}
+	return s.ExpiresAt[key]
+}
+
+func (s *DefaultSession) GetUsername() string {
+	if s == nil {
+		return ""
+	}
+	return s.Username
+}
+
+func (s *DefaultSession) GetSubject() string {
+	if s == nil {
+		return ""
+	}
+
+	return s.Subject
 }
 
 func (s *DefaultSession) IDTokenHeaders() *jwt.Headers {
diff --git a/integration/authorize_code_grant_test.go b/integration/authorize_code_grant_test.go
index 7efca21d4..1dab0ff67 100644
--- a/integration/authorize_code_grant_test.go
+++ b/integration/authorize_code_grant_test.go
@@ -5,6 +5,7 @@ import (
 
 	"net/http"
 
+	"github.com/ory-am/fosite"
 	"github.com/ory-am/fosite/compose"
 	"github.com/ory-am/fosite/handler/oauth2"
 	"github.com/stretchr/testify/assert"
@@ -21,10 +22,8 @@ func TestAuthorizeCodeFlow(t *testing.T) {
 }
 
 func runAuthorizeCodeGrantTest(t *testing.T, strategy interface{}) {
-	f := compose.Compose(new(compose.Config), fositeStore, strategy, compose.OAuth2AuthorizeExplicitFactory)
-	ts := mockServer(t, f, &mySessionData{
-		HMACSession: new(oauth2.HMACSession),
-	})
+	f := compose.Compose(new(compose.Config), fositeStore, strategy, compose.OAuth2AuthorizeExplicitFactory, compose.OAuth2TokenIntrospectionFactory)
+	ts := mockServer(t, f, &fosite.DefaultSession{})
 	defer ts.Close()
 
 	oauthClient := newOAuth2Client(ts)
diff --git a/integration/authorize_implicit_grant_test.go b/integration/authorize_implicit_grant_test.go
index f5ff7bc48..a189a38d5 100644
--- a/integration/authorize_implicit_grant_test.go
+++ b/integration/authorize_implicit_grant_test.go
@@ -8,6 +8,7 @@ import (
 	"testing"
 	"time"
 
+	"github.com/ory-am/fosite"
 	"github.com/ory-am/fosite/compose"
 	"github.com/ory-am/fosite/handler/oauth2"
 	"github.com/pkg/errors"
@@ -25,10 +26,8 @@ func TestAuthorizeImplicitFlow(t *testing.T) {
 }
 
 func runTestAuthorizeImplicitGrant(t *testing.T, strategy interface{}) {
-	f := compose.Compose(new(compose.Config), fositeStore, strategy, compose.OAuth2AuthorizeImplicitFactory)
-	ts := mockServer(t, f, &mySessionData{
-		HMACSession: new(oauth2.HMACSession),
-	})
+	f := compose.Compose(new(compose.Config), fositeStore, strategy, compose.OAuth2AuthorizeImplicitFactory, compose.OAuth2TokenIntrospectionFactory)
+	ts := mockServer(t, f, &fosite.DefaultSession{})
 	defer ts.Close()
 
 	oauthClient := newOAuth2Client(ts)
diff --git a/integration/client_credentials_grant_test.go b/integration/client_credentials_grant_test.go
index 4ddfe90fe..a1178694f 100644
--- a/integration/client_credentials_grant_test.go
+++ b/integration/client_credentials_grant_test.go
@@ -3,6 +3,7 @@ package integration_test
 import (
 	"testing"
 
+	"github.com/ory-am/fosite"
 	"github.com/ory-am/fosite/compose"
 	"github.com/ory-am/fosite/handler/oauth2"
 	"github.com/stretchr/testify/assert"
@@ -19,10 +20,8 @@ func TestClientCredentialsFlow(t *testing.T) {
 }
 
 func runClientCredentialsGrantTest(t *testing.T, strategy oauth2.AccessTokenStrategy) {
-	f := compose.Compose(new(compose.Config), fositeStore, strategy, compose.OAuth2ClientCredentialsGrantFactory)
-	ts := mockServer(t, f, &mySessionData{
-		HMACSession: new(oauth2.HMACSession),
-	})
+	f := compose.Compose(new(compose.Config), fositeStore, strategy, compose.OAuth2ClientCredentialsGrantFactory, compose.OAuth2TokenIntrospectionFactory)
+	ts := mockServer(t, f, &fosite.DefaultSession{})
 	defer ts.Close()
 
 	oauthClient := newOAuth2AppClient(ts)
diff --git a/integration/helper_endpoints_test.go b/integration/helper_endpoints_test.go
index 4050923f8..ffae03a98 100644
--- a/integration/helper_endpoints_test.go
+++ b/integration/helper_endpoints_test.go
@@ -5,7 +5,6 @@ import (
 	"testing"
 
 	"github.com/ory-am/fosite"
-	foauth "github.com/ory-am/fosite/handler/oauth2"
 	"github.com/pkg/errors"
 	"github.com/stretchr/testify/assert"
 )
@@ -14,12 +13,7 @@ type stackTracer interface {
 	StackTrace() errors.StackTrace
 }
 
-type mySessionData struct {
-	Foo string
-	*foauth.HMACSession
-}
-
-func tokenRevocationHandler(t *testing.T, oauth2 fosite.OAuth2Provider, session interface{}) func(rw http.ResponseWriter, req *http.Request) {
+func tokenRevocationHandler(t *testing.T, oauth2 fosite.OAuth2Provider, session fosite.Session) func(rw http.ResponseWriter, req *http.Request) {
 	return func(rw http.ResponseWriter, req *http.Request) {
 		ctx := fosite.NewContext()
 		err := oauth2.NewRevocationRequest(ctx, req)
@@ -31,7 +25,7 @@ func tokenRevocationHandler(t *testing.T, oauth2 fosite.OAuth2Provider, session
 	}
 }
 
-func tokenIntrospectionHandler(t *testing.T, oauth2 fosite.OAuth2Provider, session interface{}) func(rw http.ResponseWriter, req *http.Request) {
+func tokenIntrospectionHandler(t *testing.T, oauth2 fosite.OAuth2Provider, session fosite.Session) func(rw http.ResponseWriter, req *http.Request) {
 	return func(rw http.ResponseWriter, req *http.Request) {
 		ctx := fosite.NewContext()
 		ar, err := oauth2.NewIntrospectionRequest(ctx, req, session)
@@ -46,7 +40,7 @@ func tokenIntrospectionHandler(t *testing.T, oauth2 fosite.OAuth2Provider, sessi
 	}
 }
 
-func tokenInfoHandler(t *testing.T, oauth2 fosite.OAuth2Provider, session interface{}) func(rw http.ResponseWriter, req *http.Request) {
+func tokenInfoHandler(t *testing.T, oauth2 fosite.OAuth2Provider, session fosite.Session) func(rw http.ResponseWriter, req *http.Request) {
 	return func(rw http.ResponseWriter, req *http.Request) {
 		ctx := fosite.NewContext()
 		if _, err := oauth2.IntrospectToken(ctx, fosite.AccessTokenFromRequest(req), fosite.AccessToken, session); err != nil {
@@ -61,7 +55,7 @@ func tokenInfoHandler(t *testing.T, oauth2 fosite.OAuth2Provider, session interf
 	}
 }
 
-func authEndpointHandler(t *testing.T, oauth2 fosite.OAuth2Provider, session interface{}) func(rw http.ResponseWriter, req *http.Request) {
+func authEndpointHandler(t *testing.T, oauth2 fosite.OAuth2Provider, session fosite.Session) func(rw http.ResponseWriter, req *http.Request) {
 	return func(rw http.ResponseWriter, req *http.Request) {
 		ctx := fosite.NewContext()
 
@@ -124,9 +118,7 @@ func tokenEndpointHandler(t *testing.T, oauth2 fosite.OAuth2Provider) func(rw ht
 		req.ParseForm()
 		ctx := fosite.NewContext()
 
-		accessRequest, err := oauth2.NewAccessRequest(ctx, req, &mySessionData{
-			HMACSession: &foauth.HMACSession{},
-		})
+		accessRequest, err := oauth2.NewAccessRequest(ctx, req, &fosite.DefaultSession{})
 		if err != nil {
 			t.Logf("Access request failed because %s.", err.Error())
 			t.Logf("Request: %s.", accessRequest)
diff --git a/integration/helper_setup_test.go b/integration/helper_setup_test.go
index b396dd541..56de09756 100644
--- a/integration/helper_setup_test.go
+++ b/integration/helper_setup_test.go
@@ -43,7 +43,6 @@ var fositeStore = &storage.MemoryStore{
 
 type defaultSession struct {
 	*openid.DefaultSession
-	*oauth2.HMACSession
 }
 
 var accessTokenLifespan = time.Hour
@@ -80,7 +79,7 @@ var hmacStrategy = &oauth2.HMACSHAStrategy{
 	AuthorizeCodeLifespan: authCodeLifespan,
 }
 
-func mockServer(t *testing.T, f fosite.OAuth2Provider, session interface{}) *httptest.Server {
+func mockServer(t *testing.T, f fosite.OAuth2Provider, session fosite.Session) *httptest.Server {
 	router := mux.NewRouter()
 	router.HandleFunc("/auth", authEndpointHandler(t, f, session))
 	router.HandleFunc("/token", tokenEndpointHandler(t, f))
diff --git a/integration/introspect_token_test.go b/integration/introspect_token_test.go
index 1fb47d59e..923d99dbc 100644
--- a/integration/introspect_token_test.go
+++ b/integration/introspect_token_test.go
@@ -4,6 +4,7 @@ import (
 	"testing"
 
 	"encoding/json"
+	"github.com/ory-am/fosite"
 	"github.com/ory-am/fosite/compose"
 	"github.com/ory-am/fosite/handler/oauth2"
 	"github.com/parnurzeal/gorequest"
@@ -21,10 +22,8 @@ func TestIntrospectToken(t *testing.T) {
 }
 
 func runIntrospectTokenTest(t *testing.T, strategy oauth2.AccessTokenStrategy) {
-	f := compose.Compose(new(compose.Config), fositeStore, strategy, compose.OAuth2ClientCredentialsGrantFactory)
-	ts := mockServer(t, f, &mySessionData{
-		HMACSession: new(oauth2.HMACSession),
-	})
+	f := compose.Compose(new(compose.Config), fositeStore, strategy, compose.OAuth2ClientCredentialsGrantFactory, compose.OAuth2TokenIntrospectionFactory)
+	ts := mockServer(t, f, &fosite.DefaultSession{})
 	defer ts.Close()
 
 	oauthClient := newOAuth2AppClient(ts)
@@ -47,28 +46,28 @@ func runIntrospectTokenTest(t *testing.T, strategy oauth2.AccessTokenStrategy) {
 		},
 		{
 			prepare: func(s *gorequest.SuperAgent) *gorequest.SuperAgent {
-				return s.Set("Authorization", "bearer "+a.AccessToken)
+				return s.Set("Authorization", "bearer " + a.AccessToken)
 			},
 			isActive: true,
 			scopes:   "fosite",
 		},
 		{
 			prepare: func(s *gorequest.SuperAgent) *gorequest.SuperAgent {
-				return s.Set("Authorization", "bearer "+a.AccessToken)
+				return s.Set("Authorization", "bearer " + a.AccessToken)
 			},
 			isActive: true,
 			scopes:   "",
 		},
 		{
 			prepare: func(s *gorequest.SuperAgent) *gorequest.SuperAgent {
-				return s.Set("Authorization", "bearer "+a.AccessToken)
+				return s.Set("Authorization", "bearer " + a.AccessToken)
 			},
 			isActive: false,
 			scopes:   "foo",
 		},
 		{
 			prepare: func(s *gorequest.SuperAgent) *gorequest.SuperAgent {
-				return s.Set("Authorization", "bearer "+b.AccessToken)
+				return s.Set("Authorization", "bearer " + b.AccessToken)
 			},
 			isActive: false,
 			scopes:   "",
diff --git a/integration/oidc_explicit_test.go b/integration/oidc_explicit_test.go
index eb17c5cb4..934ac2335 100644
--- a/integration/oidc_explicit_test.go
+++ b/integration/oidc_explicit_test.go
@@ -20,7 +20,7 @@ func TestOpenIDConnectExplicitFlow(t *testing.T) {
 			Claims: &jwt.IDTokenClaims{
 				Subject: "peter",
 			},
-			Headers: &jwt.Headers{},
+			Headers:        &jwt.Headers{},
 		},
 	}
 	f := compose.ComposeAllEnabled(new(compose.Config), fositeStore, []byte("some-secret-thats-random"), internal.MustRSAKey())
diff --git a/integration/oidc_implicit_hybrid_test.go b/integration/oidc_implicit_hybrid_test.go
index 0817566f8..d774bfdf2 100644
--- a/integration/oidc_implicit_hybrid_test.go
+++ b/integration/oidc_implicit_hybrid_test.go
@@ -25,7 +25,7 @@ func TestOIDCImplicitFlow(t *testing.T) {
 			Claims: &jwt.IDTokenClaims{
 				Subject: "peter",
 			},
-			Headers: &jwt.Headers{},
+			Headers:        &jwt.Headers{},
 		},
 	}
 	f := compose.ComposeAllEnabled(new(compose.Config), fositeStore, []byte("some-secret-thats-random"), internal.MustRSAKey())
@@ -74,7 +74,7 @@ func TestOIDCImplicitFlow(t *testing.T) {
 		c.setup()
 
 		var callbackURL *url.URL
-		authURL := strings.Replace(oauthClient.AuthCodeURL(state), "response_type=code", "response_type="+c.responseType, -1) + "&nonce=" + c.nonce
+		authURL := strings.Replace(oauthClient.AuthCodeURL(state), "response_type=code", "response_type=" + c.responseType, -1) + "&nonce=" + c.nonce
 		client := &http.Client{
 			CheckRedirect: func(req *http.Request, via []*http.Request) error {
 				callbackURL = req.URL
diff --git a/integration/refresh_token_grant_test.go b/integration/refresh_token_grant_test.go
index 49802002e..dd8607acc 100644
--- a/integration/refresh_token_grant_test.go
+++ b/integration/refresh_token_grant_test.go
@@ -6,11 +6,12 @@ import (
 	"net/http"
 	"time"
 
+	"github.com/ory-am/fosite"
 	"github.com/ory-am/fosite/compose"
 	hst "github.com/ory-am/fosite/handler/oauth2"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
-	oauth2 "golang.org/x/oauth2"
+	"golang.org/x/oauth2"
 )
 
 func TestRefreshTokenFlow(t *testing.T) {
@@ -28,10 +29,9 @@ func runRefreshTokenGrantTest(t *testing.T, strategy interface{}) {
 		strategy,
 		compose.OAuth2AuthorizeExplicitFactory,
 		compose.OAuth2RefreshTokenGrantFactory,
+		compose.OAuth2TokenIntrospectionFactory,
 	)
-	ts := mockServer(t, f, &mySessionData{
-		HMACSession: new(hst.HMACSession),
-	})
+	ts := mockServer(t, f, &fosite.DefaultSession{})
 	defer ts.Close()
 
 	oauthClient := newOAuth2Client(ts)
@@ -66,8 +66,9 @@ func runRefreshTokenGrantTest(t *testing.T, strategy interface{}) {
 			require.Nil(t, err, "(%d) %s", k, c.description)
 			require.NotEmpty(t, token.AccessToken, "(%d) %s", k, c.description)
 
+			t.Logf("Token %s\n", token)
 			token.Expiry = token.Expiry.Add(-time.Hour * 24)
-			t.Logf("Token %s", token)
+			t.Logf("Token %s\n", token)
 
 			tokenSource := oauthClient.TokenSource(oauth2.NoContext, token)
 			refreshed, err := tokenSource.Token()
diff --git a/integration/resource_owner_password_credentials_grant_test.go b/integration/resource_owner_password_credentials_grant_test.go
index 84ccbdf63..f4041224f 100644
--- a/integration/resource_owner_password_credentials_grant_test.go
+++ b/integration/resource_owner_password_credentials_grant_test.go
@@ -3,6 +3,7 @@ package integration_test
 import (
 	"testing"
 
+	"github.com/ory-am/fosite"
 	"github.com/ory-am/fosite/compose"
 	hst "github.com/ory-am/fosite/handler/oauth2"
 	"github.com/stretchr/testify/assert"
@@ -20,9 +21,7 @@ func TestResourceOwnerPasswordCredentialsFlow(t *testing.T) {
 
 func runResourceOwnerPasswordCredentialsGrantTest(t *testing.T, strategy hst.AccessTokenStrategy) {
 	f := compose.Compose(new(compose.Config), fositeStore, strategy, compose.OAuth2ResourceOwnerPasswordCredentialsFactory)
-	ts := mockServer(t, f, &mySessionData{
-		HMACSession: new(hst.HMACSession),
-	})
+	ts := mockServer(t, f, &fosite.DefaultSession{})
 	defer ts.Close()
 
 	var username, password string
diff --git a/integration/revoke_token_test.go b/integration/revoke_token_test.go
index e64c6224c..1f333bc12 100644
--- a/integration/revoke_token_test.go
+++ b/integration/revoke_token_test.go
@@ -3,6 +3,7 @@ package integration_test
 import (
 	"testing"
 
+	"github.com/ory-am/fosite"
 	"github.com/ory-am/fosite/compose"
 	"github.com/ory-am/fosite/handler/oauth2"
 	"github.com/parnurzeal/gorequest"
@@ -21,32 +22,30 @@ func TestRevokeToken(t *testing.T) {
 }
 
 func runRevokeTokenTest(t *testing.T, strategy oauth2.AccessTokenStrategy) {
-	f := compose.Compose(new(compose.Config), fositeStore, strategy, compose.OAuth2ClientCredentialsGrantFactory, compose.OAuth2TokenRevocationFactory)
-	ts := mockServer(t, f, &mySessionData{
-		HMACSession: new(oauth2.HMACSession),
-	})
+	f := compose.Compose(new(compose.Config), fositeStore, strategy, compose.OAuth2ClientCredentialsGrantFactory, compose.OAuth2TokenIntrospectionFactory, compose.OAuth2TokenRevocationFactory)
+	ts := mockServer(t, f, &fosite.DefaultSession{})
 	defer ts.Close()
 
 	oauthClient := newOAuth2AppClient(ts)
 	token, err := oauthClient.Token(goauth.NoContext)
 	assert.Nil(t, err)
 
-	resp, _, errs := gorequest.New().Post(ts.URL+"/revoke").
+	resp, _, errs := gorequest.New().Post(ts.URL + "/revoke").
 		SetBasicAuth(oauthClient.ClientID, oauthClient.ClientSecret).
 		Type("form").
 		SendStruct(map[string]string{"token": "asdf"}).End()
 	assert.Len(t, errs, 0)
 	assert.Equal(t, 200, resp.StatusCode)
 
-	resp, _, errs = gorequest.New().Post(ts.URL+"/revoke").
+	resp, _, errs = gorequest.New().Post(ts.URL + "/revoke").
 		SetBasicAuth(oauthClient.ClientID, oauthClient.ClientSecret).
 		Type("form").
 		SendStruct(map[string]string{"token": token.AccessToken}).End()
 	assert.Len(t, errs, 0)
 	assert.Equal(t, 200, resp.StatusCode)
 
-	hres, _, errs := gorequest.New().Get(ts.URL+"/info").
-		Set("Authorization", "bearer "+token.AccessToken).
+	hres, _, errs := gorequest.New().Get(ts.URL + "/info").
+		Set("Authorization", "bearer " + token.AccessToken).
 		End()
 	require.Len(t, errs, 0)
 	assert.Equal(t, http.StatusUnauthorized, hres.StatusCode)
diff --git a/internal/access_request.go b/internal/access_request.go
index b2cf6d0f2..1e243513f 100644
--- a/internal/access_request.go
+++ b/internal/access_request.go
@@ -109,9 +109,9 @@ func (_mr *_MockAccessRequesterRecorder) GetRequestedScopes() *gomock.Call {
 	return _mr.mock.ctrl.RecordCall(_mr.mock, "GetRequestedScopes")
 }
 
-func (_m *MockAccessRequester) GetSession() interface{} {
+func (_m *MockAccessRequester) GetSession() fosite.Session {
 	ret := _m.ctrl.Call(_m, "GetSession")
-	ret0, _ := ret[0].(interface{})
+	ret0, _ := ret[0].(fosite.Session)
 	return ret0
 }
 
@@ -143,7 +143,7 @@ func (_mr *_MockAccessRequesterRecorder) SetRequestedScopes(arg0 interface{}) *g
 	return _mr.mock.ctrl.RecordCall(_mr.mock, "SetRequestedScopes", arg0)
 }
 
-func (_m *MockAccessRequester) SetSession(_param0 interface{}) {
+func (_m *MockAccessRequester) SetSession(_param0 fosite.Session) {
 	_m.ctrl.Call(_m, "SetSession", _param0)
 }
 
diff --git a/internal/access_token_storage.go b/internal/access_token_storage.go
index 7ce1df1e0..3956edace 100644
--- a/internal/access_token_storage.go
+++ b/internal/access_token_storage.go
@@ -50,7 +50,7 @@ func (_mr *_MockAccessTokenStorageRecorder) DeleteAccessTokenSession(arg0, arg1
 	return _mr.mock.ctrl.RecordCall(_mr.mock, "DeleteAccessTokenSession", arg0, arg1)
 }
 
-func (_m *MockAccessTokenStorage) GetAccessTokenSession(_param0 context.Context, _param1 string, _param2 interface{}) (fosite.Requester, error) {
+func (_m *MockAccessTokenStorage) GetAccessTokenSession(_param0 context.Context, _param1 string, _param2 fosite.Session) (fosite.Requester, error) {
 	ret := _m.ctrl.Call(_m, "GetAccessTokenSession", _param0, _param1, _param2)
 	ret0, _ := ret[0].(fosite.Requester)
 	ret1, _ := ret[1].(error)
diff --git a/internal/authorize_code_storage.go b/internal/authorize_code_storage.go
index f8269e45e..ef7431901 100644
--- a/internal/authorize_code_storage.go
+++ b/internal/authorize_code_storage.go
@@ -50,7 +50,7 @@ func (_mr *_MockAuthorizeCodeStorageRecorder) DeleteAuthorizeCodeSession(arg0, a
 	return _mr.mock.ctrl.RecordCall(_mr.mock, "DeleteAuthorizeCodeSession", arg0, arg1)
 }
 
-func (_m *MockAuthorizeCodeStorage) GetAuthorizeCodeSession(_param0 context.Context, _param1 string, _param2 interface{}) (fosite.Requester, error) {
+func (_m *MockAuthorizeCodeStorage) GetAuthorizeCodeSession(_param0 context.Context, _param1 string, _param2 fosite.Session) (fosite.Requester, error) {
 	ret := _m.ctrl.Call(_m, "GetAuthorizeCodeSession", _param0, _param1, _param2)
 	ret0, _ := ret[0].(fosite.Requester)
 	ret1, _ := ret[1].(error)
diff --git a/internal/authorize_request.go b/internal/authorize_request.go
index 74179534e..46174ddd0 100644
--- a/internal/authorize_request.go
+++ b/internal/authorize_request.go
@@ -129,9 +129,9 @@ func (_mr *_MockAuthorizeRequesterRecorder) GetResponseTypes() *gomock.Call {
 	return _mr.mock.ctrl.RecordCall(_mr.mock, "GetResponseTypes")
 }
 
-func (_m *MockAuthorizeRequester) GetSession() interface{} {
+func (_m *MockAuthorizeRequester) GetSession() fosite.Session {
 	ret := _m.ctrl.Call(_m, "GetSession")
-	ret0, _ := ret[0].(interface{})
+	ret0, _ := ret[0].(fosite.Session)
 	return ret0
 }
 
@@ -191,7 +191,7 @@ func (_mr *_MockAuthorizeRequesterRecorder) SetResponseTypeHandled(arg0 interfac
 	return _mr.mock.ctrl.RecordCall(_mr.mock, "SetResponseTypeHandled", arg0)
 }
 
-func (_m *MockAuthorizeRequester) SetSession(_param0 interface{}) {
+func (_m *MockAuthorizeRequester) SetSession(_param0 fosite.Session) {
 	_m.ctrl.Call(_m, "SetSession", _param0)
 }
 
diff --git a/internal/oauth2_client_storage.go b/internal/oauth2_client_storage.go
index 7a7dcc6c1..491986fd4 100644
--- a/internal/oauth2_client_storage.go
+++ b/internal/oauth2_client_storage.go
@@ -50,7 +50,7 @@ func (_mr *_MockClientCredentialsGrantStorageRecorder) DeleteAccessTokenSession(
 	return _mr.mock.ctrl.RecordCall(_mr.mock, "DeleteAccessTokenSession", arg0, arg1)
 }
 
-func (_m *MockClientCredentialsGrantStorage) GetAccessTokenSession(_param0 context.Context, _param1 string, _param2 interface{}) (fosite.Requester, error) {
+func (_m *MockClientCredentialsGrantStorage) GetAccessTokenSession(_param0 context.Context, _param1 string, _param2 fosite.Session) (fosite.Requester, error) {
 	ret := _m.ctrl.Call(_m, "GetAccessTokenSession", _param0, _param1, _param2)
 	ret0, _ := ret[0].(fosite.Requester)
 	ret1, _ := ret[1].(error)
diff --git a/internal/oauth2_explicit_storage.go b/internal/oauth2_explicit_storage.go
index 4f77e35bc..6aa44afe1 100644
--- a/internal/oauth2_explicit_storage.go
+++ b/internal/oauth2_explicit_storage.go
@@ -50,7 +50,7 @@ func (_mr *_MockAuthorizeCodeGrantStorageRecorder) DeleteAuthorizeCodeSession(ar
 	return _mr.mock.ctrl.RecordCall(_mr.mock, "DeleteAuthorizeCodeSession", arg0, arg1)
 }
 
-func (_m *MockAuthorizeCodeGrantStorage) GetAuthorizeCodeSession(_param0 context.Context, _param1 string, _param2 interface{}) (fosite.Requester, error) {
+func (_m *MockAuthorizeCodeGrantStorage) GetAuthorizeCodeSession(_param0 context.Context, _param1 string, _param2 fosite.Session) (fosite.Requester, error) {
 	ret := _m.ctrl.Call(_m, "GetAuthorizeCodeSession", _param0, _param1, _param2)
 	ret0, _ := ret[0].(fosite.Requester)
 	ret1, _ := ret[1].(error)
diff --git a/internal/oauth2_owner_storage.go b/internal/oauth2_owner_storage.go
index 6c147d7fa..6e13fac85 100644
--- a/internal/oauth2_owner_storage.go
+++ b/internal/oauth2_owner_storage.go
@@ -80,7 +80,7 @@ func (_mr *_MockResourceOwnerPasswordCredentialsGrantStorageRecorder) DeleteRefr
 	return _mr.mock.ctrl.RecordCall(_mr.mock, "DeleteRefreshTokenSession", arg0, arg1)
 }
 
-func (_m *MockResourceOwnerPasswordCredentialsGrantStorage) GetAccessTokenSession(_param0 context.Context, _param1 string, _param2 interface{}) (fosite.Requester, error) {
+func (_m *MockResourceOwnerPasswordCredentialsGrantStorage) GetAccessTokenSession(_param0 context.Context, _param1 string, _param2 fosite.Session) (fosite.Requester, error) {
 	ret := _m.ctrl.Call(_m, "GetAccessTokenSession", _param0, _param1, _param2)
 	ret0, _ := ret[0].(fosite.Requester)
 	ret1, _ := ret[1].(error)
@@ -91,7 +91,7 @@ func (_mr *_MockResourceOwnerPasswordCredentialsGrantStorageRecorder) GetAccessT
 	return _mr.mock.ctrl.RecordCall(_mr.mock, "GetAccessTokenSession", arg0, arg1, arg2)
 }
 
-func (_m *MockResourceOwnerPasswordCredentialsGrantStorage) GetRefreshTokenSession(_param0 context.Context, _param1 string, _param2 interface{}) (fosite.Requester, error) {
+func (_m *MockResourceOwnerPasswordCredentialsGrantStorage) GetRefreshTokenSession(_param0 context.Context, _param1 string, _param2 fosite.Session) (fosite.Requester, error) {
 	ret := _m.ctrl.Call(_m, "GetRefreshTokenSession", _param0, _param1, _param2)
 	ret0, _ := ret[0].(fosite.Requester)
 	ret1, _ := ret[1].(error)
diff --git a/internal/oauth2_refresh_storage.go b/internal/oauth2_refresh_storage.go
index 2228abaa3..7f8d652e8 100644
--- a/internal/oauth2_refresh_storage.go
+++ b/internal/oauth2_refresh_storage.go
@@ -50,7 +50,7 @@ func (_mr *_MockRefreshTokenGrantStorageRecorder) DeleteRefreshTokenSession(arg0
 	return _mr.mock.ctrl.RecordCall(_mr.mock, "DeleteRefreshTokenSession", arg0, arg1)
 }
 
-func (_m *MockRefreshTokenGrantStorage) GetRefreshTokenSession(_param0 context.Context, _param1 string, _param2 interface{}) (fosite.Requester, error) {
+func (_m *MockRefreshTokenGrantStorage) GetRefreshTokenSession(_param0 context.Context, _param1 string, _param2 fosite.Session) (fosite.Requester, error) {
 	ret := _m.ctrl.Call(_m, "GetRefreshTokenSession", _param0, _param1, _param2)
 	ret0, _ := ret[0].(fosite.Requester)
 	ret1, _ := ret[1].(error)
diff --git a/internal/oauth2_revoke_storage.go b/internal/oauth2_revoke_storage.go
index 00ac2ad79..19e63dc2b 100644
--- a/internal/oauth2_revoke_storage.go
+++ b/internal/oauth2_revoke_storage.go
@@ -70,7 +70,7 @@ func (_mr *_MockTokenRevocationStorageRecorder) DeleteRefreshTokenSession(arg0,
 	return _mr.mock.ctrl.RecordCall(_mr.mock, "DeleteRefreshTokenSession", arg0, arg1)
 }
 
-func (_m *MockTokenRevocationStorage) GetAccessTokenSession(_param0 context.Context, _param1 string, _param2 interface{}) (fosite.Requester, error) {
+func (_m *MockTokenRevocationStorage) GetAccessTokenSession(_param0 context.Context, _param1 string, _param2 fosite.Session) (fosite.Requester, error) {
 	ret := _m.ctrl.Call(_m, "GetAccessTokenSession", _param0, _param1, _param2)
 	ret0, _ := ret[0].(fosite.Requester)
 	ret1, _ := ret[1].(error)
@@ -81,7 +81,7 @@ func (_mr *_MockTokenRevocationStorageRecorder) GetAccessTokenSession(arg0, arg1
 	return _mr.mock.ctrl.RecordCall(_mr.mock, "GetAccessTokenSession", arg0, arg1, arg2)
 }
 
-func (_m *MockTokenRevocationStorage) GetRefreshTokenSession(_param0 context.Context, _param1 string, _param2 interface{}) (fosite.Requester, error) {
+func (_m *MockTokenRevocationStorage) GetRefreshTokenSession(_param0 context.Context, _param1 string, _param2 fosite.Session) (fosite.Requester, error) {
 	ret := _m.ctrl.Call(_m, "GetRefreshTokenSession", _param0, _param1, _param2)
 	ret0, _ := ret[0].(fosite.Requester)
 	ret1, _ := ret[1].(error)
diff --git a/internal/oauth2_storage.go b/internal/oauth2_storage.go
index 8f4ecccdd..416df3970 100644
--- a/internal/oauth2_storage.go
+++ b/internal/oauth2_storage.go
@@ -90,7 +90,7 @@ func (_mr *_MockCoreStorageRecorder) DeleteRefreshTokenSession(arg0, arg1 interf
 	return _mr.mock.ctrl.RecordCall(_mr.mock, "DeleteRefreshTokenSession", arg0, arg1)
 }
 
-func (_m *MockCoreStorage) GetAccessTokenSession(_param0 context.Context, _param1 string, _param2 interface{}) (fosite.Requester, error) {
+func (_m *MockCoreStorage) GetAccessTokenSession(_param0 context.Context, _param1 string, _param2 fosite.Session) (fosite.Requester, error) {
 	ret := _m.ctrl.Call(_m, "GetAccessTokenSession", _param0, _param1, _param2)
 	ret0, _ := ret[0].(fosite.Requester)
 	ret1, _ := ret[1].(error)
@@ -101,7 +101,7 @@ func (_mr *_MockCoreStorageRecorder) GetAccessTokenSession(arg0, arg1, arg2 inte
 	return _mr.mock.ctrl.RecordCall(_mr.mock, "GetAccessTokenSession", arg0, arg1, arg2)
 }
 
-func (_m *MockCoreStorage) GetAuthorizeCodeSession(_param0 context.Context, _param1 string, _param2 interface{}) (fosite.Requester, error) {
+func (_m *MockCoreStorage) GetAuthorizeCodeSession(_param0 context.Context, _param1 string, _param2 fosite.Session) (fosite.Requester, error) {
 	ret := _m.ctrl.Call(_m, "GetAuthorizeCodeSession", _param0, _param1, _param2)
 	ret0, _ := ret[0].(fosite.Requester)
 	ret1, _ := ret[1].(error)
@@ -112,7 +112,7 @@ func (_mr *_MockCoreStorageRecorder) GetAuthorizeCodeSession(arg0, arg1, arg2 in
 	return _mr.mock.ctrl.RecordCall(_mr.mock, "GetAuthorizeCodeSession", arg0, arg1, arg2)
 }
 
-func (_m *MockCoreStorage) GetRefreshTokenSession(_param0 context.Context, _param1 string, _param2 interface{}) (fosite.Requester, error) {
+func (_m *MockCoreStorage) GetRefreshTokenSession(_param0 context.Context, _param1 string, _param2 fosite.Session) (fosite.Requester, error) {
 	ret := _m.ctrl.Call(_m, "GetRefreshTokenSession", _param0, _param1, _param2)
 	ret0, _ := ret[0].(fosite.Requester)
 	ret1, _ := ret[1].(error)
diff --git a/internal/request.go b/internal/request.go
index f26ad3366..2f4603330 100644
--- a/internal/request.go
+++ b/internal/request.go
@@ -99,9 +99,9 @@ func (_mr *_MockRequesterRecorder) GetRequestedScopes() *gomock.Call {
 	return _mr.mock.ctrl.RecordCall(_mr.mock, "GetRequestedScopes")
 }
 
-func (_m *MockRequester) GetSession() interface{} {
+func (_m *MockRequester) GetSession() fosite.Session {
 	ret := _m.ctrl.Call(_m, "GetSession")
-	ret0, _ := ret[0].(interface{})
+	ret0, _ := ret[0].(fosite.Session)
 	return ret0
 }
 
@@ -133,7 +133,7 @@ func (_mr *_MockRequesterRecorder) SetRequestedScopes(arg0 interface{}) *gomock.
 	return _mr.mock.ctrl.RecordCall(_mr.mock, "SetRequestedScopes", arg0)
 }
 
-func (_m *MockRequester) SetSession(_param0 interface{}) {
+func (_m *MockRequester) SetSession(_param0 fosite.Session) {
 	_m.ctrl.Call(_m, "SetSession", _param0)
 }
 
diff --git a/introspect.go b/introspect.go
index 3577430ed..408f98e99 100644
--- a/introspect.go
+++ b/introspect.go
@@ -22,7 +22,7 @@ func AccessTokenFromRequest(req *http.Request) string {
 	return split[1]
 }
 
-func (f *Fosite) IntrospectToken(ctx context.Context, token string, tokenType TokenType, session interface{}, scopes ...string) (AccessRequester, error) {
+func (f *Fosite) IntrospectToken(ctx context.Context, token string, tokenType TokenType, session Session, scopes ...string) (AccessRequester, error) {
 	var found bool = false
 
 	ar := NewAccessRequest(session)
diff --git a/introspection_request_handler.go b/introspection_request_handler.go
index 128f9c15f..29f273c56 100644
--- a/introspection_request_handler.go
+++ b/introspection_request_handler.go
@@ -5,7 +5,6 @@ import (
 	"golang.org/x/net/context"
 	"net/http"
 	"strings"
-	"time"
 )
 
 // NewIntrospectionRequest initiates token introspection as defined in
@@ -87,7 +86,7 @@ import (
 //	Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
 //
 //	token=mF_9.B5f-4.1JqM&token_type_hint=access_token
-func (f *Fosite) NewIntrospectionRequest(ctx context.Context, r *http.Request, session interface{}) (IntrospectionResponder, error) {
+func (f *Fosite) NewIntrospectionRequest(ctx context.Context, r *http.Request, session Session) (IntrospectionResponder, error) {
 	if r.Method != "POST" {
 		return nil, errors.Wrap(ErrInvalidRequest, "HTTP method is not POST")
 	} else if err := r.ParseForm(); err != nil {
@@ -134,9 +133,8 @@ func (f *Fosite) NewIntrospectionRequest(ctx context.Context, r *http.Request, s
 }
 
 type IntrospectionResponse struct {
-	Active          bool
-	AccessRequester AccessRequester
-	ExpiresAt       time.Time
+	Active          bool            `json:"active"`
+	AccessRequester AccessRequester `json:",extra"`
 }
 
 func (r *IntrospectionResponse) IsActive() bool {
@@ -146,7 +144,3 @@ func (r *IntrospectionResponse) IsActive() bool {
 func (r *IntrospectionResponse) GetAccessRequester() AccessRequester {
 	return r.AccessRequester
 }
-
-func (r *IntrospectionResponse) GetExpiresAt() time.Time {
-	return r.ExpiresAt
-}
diff --git a/introspection_request_handler_test.go b/introspection_request_handler_test.go
index 1728e715a..8e4a74507 100644
--- a/introspection_request_handler_test.go
+++ b/introspection_request_handler_test.go
@@ -3,28 +3,24 @@ package fosite_test
 import (
 	"github.com/golang/mock/gomock"
 	"github.com/ory-am/fosite"
+	. "github.com/ory-am/fosite"
 	"github.com/ory-am/fosite/compose"
 	"github.com/ory-am/fosite/internal"
+	"github.com/ory-am/fosite/storage"
+	"github.com/pkg/errors"
 	"github.com/stretchr/testify/assert"
 	"net/http"
 	"net/url"
 	"testing"
-	"time"
-
-	. "github.com/ory-am/fosite"
-	"github.com/ory-am/fosite/storage"
-	"github.com/pkg/errors"
 )
 
 func TestIntrospectionResponse(t *testing.T) {
 	r := &fosite.IntrospectionResponse{
 		AccessRequester: fosite.NewAccessRequest(nil),
-		ExpiresAt:       time.Now(),
 		Active:          true,
 	}
 
 	assert.Equal(t, r.AccessRequester, r.GetAccessRequester())
-	assert.Equal(t, r.ExpiresAt, r.GetExpiresAt())
 	assert.Equal(t, r.Active, r.IsActive())
 }
 
diff --git a/introspection_response_writer.go b/introspection_response_writer.go
index 4d95fefc8..a5e4914a5 100644
--- a/introspection_response_writer.go
+++ b/introspection_response_writer.go
@@ -179,18 +179,22 @@ func (f *Fosite) WriteIntrospectionResponse(rw http.ResponseWriter, r Introspect
 	}
 
 	_ = json.NewEncoder(rw).Encode(struct {
-		Active    bool        `json:"active"`
-		ClientID  string      `json:"client_id"`
-		Scope     string      `json:"scope"`
-		ExpiresAt int64       `json:"exp"`
-		IssuedAt  int64       `json:"iat"`
-		Extra     interface{} `json:",inline"`
+		Active    bool    `json:"active"`
+		ClientID  string  `json:"client_id,omitempty"`
+		Scope     string  `json:"scope,omitempty"`
+		ExpiresAt int64   `json:"exp,omitempty"`
+		IssuedAt  int64   `json:"iat,omitempty"`
+		Subject   string  `json:"sub,omitempty"`
+		Username  string  `json:"username,omitempty"`
+		Session   Session `json:"sess"`
 	}{
 		Active:    true,
 		ClientID:  r.GetAccessRequester().GetClient().GetID(),
 		Scope:     strings.Join(r.GetAccessRequester().GetGrantedScopes(), " "),
-		ExpiresAt: r.GetExpiresAt().Unix(),
+		ExpiresAt: r.GetAccessRequester().GetSession().GetExpiresAt(AccessToken).Unix(),
 		IssuedAt:  r.GetAccessRequester().GetRequestedAt().Unix(),
-		Extra:     r.GetAccessRequester().GetSession(),
+		Subject:   r.GetAccessRequester().GetSession().GetSubject(),
+		Username:  r.GetAccessRequester().GetSession().GetUsername(),
+		Session:   r.GetAccessRequester().GetSession(),
 	})
 }
diff --git a/oauth2.go b/oauth2.go
index 835f675e6..74af39e82 100644
--- a/oauth2.go
+++ b/oauth2.go
@@ -52,7 +52,7 @@ type OAuth2Provider interface {
 	//	 If an authorization request is missing the "response_type" parameter,
 	//	 or if the response type is not understood, the authorization server
 	//	 MUST return an error response as described in Section 4.1.2.1.
-	NewAuthorizeResponse(ctx context.Context, req *http.Request, requester AuthorizeRequester, session interface{}) (AuthorizeResponder, error)
+	NewAuthorizeResponse(ctx context.Context, req *http.Request, requester AuthorizeRequester, session Session) (AuthorizeResponder, error)
 
 	// WriteAuthorizeError returns the error codes to the redirection endpoint or shows the error to the user, if no valid
 	// redirect uri was given. Implements rfc6749#section-4.1.2.1
@@ -91,7 +91,7 @@ type OAuth2Provider interface {
 	// * https://tools.ietf.org/html/rfc6749#section-3.2.1 (everything)
 	//
 	// Furthermore the registered handlers should implement their specs accordingly.
-	NewAccessRequest(ctx context.Context, req *http.Request, session interface{}) (AccessRequester, error)
+	NewAccessRequest(ctx context.Context, req *http.Request, session Session) (AccessRequester, error)
 
 	// NewAccessResponse creates a new access response and validates that access_token and token_type are set.
 	//
@@ -125,11 +125,11 @@ type OAuth2Provider interface {
 
 	// IntrospectToken returns token metadata, if the token is valid. Tokens generated by the authorization endpoint,
 	// such as the authorization code, can not be introspected.
-	IntrospectToken(ctx context.Context, token string, tokenType TokenType, session interface{}, scope ...string) (AccessRequester, error)
+	IntrospectToken(ctx context.Context, token string, tokenType TokenType, session Session, scope ...string) (AccessRequester, error)
 
 	// NewIntrospectionRequest initiates token introspection as defined in
 	// https://tools.ietf.org/search/rfc7662#section-2.1
-	NewIntrospectionRequest(ctx context.Context, r *http.Request, session interface{}) (IntrospectionResponder, error)
+	NewIntrospectionRequest(ctx context.Context, r *http.Request, session Session) (IntrospectionResponder, error)
 
 	// WriteIntrospectionError responds with an error if token introspection failed as defined in
 	// https://tools.ietf.org/search/rfc7662#section-2.3
@@ -149,9 +149,6 @@ type IntrospectionResponder interface {
 
 	// AccessRequester returns nil when IsActive() is false and the original access request object otherwise.
 	GetAccessRequester() AccessRequester
-
-	// GetExpiresAt returns the expiration date.
-	GetExpiresAt() time.Time
 }
 
 // Requester is an abstract interface for handling requests in Fosite.
@@ -181,10 +178,10 @@ type Requester interface {
 	GrantScope(scope string)
 
 	// GetSession returns a pointer to the request's session or nil if none is set.
-	GetSession() (session interface{})
+	GetSession() (session Session)
 
 	// GetSession sets the request's session pointer.
-	SetSession(session interface{})
+	SetSession(session Session)
 
 	// GetRequestForm returns the request's form input.
 	GetRequestForm() url.Values
diff --git a/request.go b/request.go
index 44f4f94d5..38c70c2e5 100644
--- a/request.go
+++ b/request.go
@@ -9,13 +9,13 @@ import (
 
 // Request is an implementation of Requester
 type Request struct {
-	ID            string      `json:"id" gorethink:"id"`
-	RequestedAt   time.Time   `json:"requestedAt" gorethink:"requestedAt"`
-	Client        Client      `json:"client" gorethink:"client"`
-	Scopes        Arguments   `json:"scopes" gorethink:"scopes"`
-	GrantedScopes Arguments   `json:"grantedScopes" gorethink:"grantedScopes"`
-	Form          url.Values  `json:"form" gorethink:"form"`
-	Session       interface{} `json:"session" gorethink:"session"`
+	ID            string     `json:"id" gorethink:"id"`
+	RequestedAt   time.Time  `json:"requestedAt" gorethink:"requestedAt"`
+	Client        Client     `json:"client" gorethink:"client"`
+	Scopes        Arguments  `json:"scopes" gorethink:"scopes"`
+	GrantedScopes Arguments  `json:"grantedScopes" gorethink:"grantedScopes"`
+	Form          url.Values `json:"form" gorethink:"form"`
+	Session       Session    `json:"session" gorethink:"session"`
 }
 
 func NewRequest() *Request {
@@ -79,11 +79,11 @@ func (a *Request) GrantScope(scope string) {
 	a.GrantedScopes = append(a.GrantedScopes, scope)
 }
 
-func (a *Request) SetSession(session interface{}) {
+func (a *Request) SetSession(session Session) {
 	a.Session = session
 }
 
-func (a *Request) GetSession() interface{} {
+func (a *Request) GetSession() Session {
 	return a.Session
 }
 
diff --git a/request_test.go b/request_test.go
index 2027ad7ee..2517f0180 100644
--- a/request_test.go
+++ b/request_test.go
@@ -16,7 +16,7 @@ func TestRequest(t *testing.T) {
 		Scopes:        Arguments{},
 		GrantedScopes: []string{},
 		Form:          url.Values{"foo": []string{"bar"}},
-		Session:       1234,
+		Session:       new(DefaultSession),
 	}
 
 	assert.Equal(t, r.RequestedAt, r.GetRequestedAt())
@@ -34,7 +34,7 @@ func TestMergeRequest(t *testing.T) {
 		Scopes:        Arguments{"asdff"},
 		GrantedScopes: []string{"asdf"},
 		Form:          url.Values{"foo": []string{"fasdf"}},
-		Session:       54321,
+		Session:       new(DefaultSession),
 	}
 	b := &Request{
 		RequestedAt:   time.Now(),
@@ -42,7 +42,7 @@ func TestMergeRequest(t *testing.T) {
 		Scopes:        Arguments{},
 		GrantedScopes: []string{},
 		Form:          url.Values{},
-		Session:       12345,
+		Session:       new(DefaultSession),
 	}
 
 	b.Merge(a)
diff --git a/session.go b/session.go
new file mode 100644
index 000000000..2bf313fd4
--- /dev/null
+++ b/session.go
@@ -0,0 +1,63 @@
+package fosite
+
+import "time"
+
+// Session is an interface that is used to store session data between OAuth2 requests. It can be used to look up
+// when a session expires or what the subject's name was.
+type Session interface {
+	// SetExpiresAt sets the expiration time of a token.
+	//
+	//  session.SetExpiresAt(fosite.AccessToken, time.Now().Add(time.Hour))
+	SetExpiresAt(key TokenType, exp time.Time)
+
+	// SetExpiresAt returns expiration time of a token if set, or time.IsZero() if not.
+	//
+	//  session.GetExpiresAt(fosite.AccessToken)
+	GetExpiresAt(key TokenType) time.Time
+
+	// GetUsername returns the username, if set. This is optional and only used during token introspection.
+	GetUsername() string
+
+	// GetSubject returns the subject, if set. This is optional and only used during token introspection.
+	GetSubject() string
+}
+
+// DefaultSession is a default implementation of the session interface.
+type DefaultSession struct {
+	ExpiresAt map[TokenType]time.Time
+	Username  string
+	Subject   string
+}
+
+func (s *DefaultSession) SetExpiresAt(key TokenType, exp time.Time) {
+	if s.ExpiresAt == nil {
+		s.ExpiresAt = make(map[TokenType]time.Time)
+	}
+	s.ExpiresAt[key] = exp
+}
+
+func (s *DefaultSession) GetExpiresAt(key TokenType) time.Time {
+	if s.ExpiresAt == nil {
+		s.ExpiresAt = make(map[TokenType]time.Time)
+	}
+
+	if _, ok := s.ExpiresAt[key]; !ok {
+		return time.Time{}
+	}
+	return s.ExpiresAt[key]
+}
+
+func (s *DefaultSession) GetUsername() string {
+	if s == nil {
+		return ""
+	}
+	return s.Username
+}
+
+func (s *DefaultSession) GetSubject() string {
+	if s == nil {
+		return ""
+	}
+
+	return s.Subject
+}
diff --git a/storage/memory.go b/storage/memory.go
index e9e941492..13e35a203 100644
--- a/storage/memory.go
+++ b/storage/memory.go
@@ -99,7 +99,7 @@ func (s *MemoryStore) CreateAuthorizeCodeSession(_ context.Context, code string,
 	return nil
 }
 
-func (s *MemoryStore) GetAuthorizeCodeSession(_ context.Context, code string, _ interface{}) (fosite.Requester, error) {
+func (s *MemoryStore) GetAuthorizeCodeSession(_ context.Context, code string, _ fosite.Session) (fosite.Requester, error) {
 	rel, ok := s.AuthorizeCodes[code]
 	if !ok {
 		return nil, fosite.ErrNotFound
@@ -118,7 +118,7 @@ func (s *MemoryStore) CreateAccessTokenSession(_ context.Context, signature stri
 	return nil
 }
 
-func (s *MemoryStore) GetAccessTokenSession(_ context.Context, signature string, _ interface{}) (fosite.Requester, error) {
+func (s *MemoryStore) GetAccessTokenSession(_ context.Context, signature string, _ fosite.Session) (fosite.Requester, error) {
 	rel, ok := s.AccessTokens[signature]
 	if !ok {
 		return nil, fosite.ErrNotFound
@@ -137,7 +137,7 @@ func (s *MemoryStore) CreateRefreshTokenSession(_ context.Context, signature str
 	return nil
 }
 
-func (s *MemoryStore) GetRefreshTokenSession(_ context.Context, signature string, _ interface{}) (fosite.Requester, error) {
+func (s *MemoryStore) GetRefreshTokenSession(_ context.Context, signature string, _ fosite.Session) (fosite.Requester, error) {
 	rel, ok := s.RefreshTokens[signature]
 	if !ok {
 		return nil, fosite.ErrNotFound