diff --git a/connector/oidc/oidc.go b/connector/oidc/oidc.go
index 14329c0040d8a7bad3121d018752c66192f9d9b9..ff4713c270564088314fdd069f17de51c22cced4 100644
--- a/connector/oidc/oidc.go
+++ b/connector/oidc/oidc.go
@@ -301,6 +301,7 @@ func (c *oidcConnector) TokenIdentity(ctx context.Context, subjectTokenType, sub
 	var identity connector.Identity
 	token := &oauth2.Token{
 		AccessToken: subjectToken,
+		TokenType:   subjectTokenType,
 	}
 	return c.createIdentity(ctx, identity, token, exchangeCaller)
 }
@@ -318,20 +319,30 @@ func (c *oidcConnector) createIdentity(ctx context.Context, identity connector.I
 			return identity, fmt.Errorf("oidc: failed to decode claims: %v", err)
 		}
 	} else if caller == exchangeCaller {
-		// AccessToken here could be either an id token or an access token
-		idToken, err := c.provider.Verifier(&oidc.Config{SkipClientIDCheck: true}).Verify(ctx, token.AccessToken)
-		if err != nil {
-			return identity, fmt.Errorf("oidc: failed to verify token: %v", err)
-		}
-		if err := idToken.Claims(&claims); err != nil {
-			return identity, fmt.Errorf("oidc: failed to decode claims: %v", err)
+		switch token.TokenType {
+		case "urn:ietf:params:oauth:token-type:id_token":
+			// Verify only works on ID tokens
+			idToken, err := c.provider.Verifier(&oidc.Config{SkipClientIDCheck: true}).Verify(ctx, token.AccessToken)
+			if err != nil {
+				return identity, fmt.Errorf("oidc: failed to verify token: %v", err)
+			}
+			if err := idToken.Claims(&claims); err != nil {
+				return identity, fmt.Errorf("oidc: failed to decode claims: %v", err)
+			}
+		case "urn:ietf:params:oauth:token-type:access_token":
+			if !c.getUserInfo {
+				return identity, fmt.Errorf("oidc: getUserInfo is required for access token exchange")
+			}
+		default:
+			return identity, fmt.Errorf("unknown token type for token exchange: %s", token.TokenType)
 		}
 	} else if caller != refreshCaller {
 		// ID tokens aren't mandatory in the reply when using a refresh_token grant
 		return identity, errors.New("oidc: no id_token in token response")
 	}
 
-	// We immediately want to run getUserInfo if configured before we validate the claims
+	// We immediately want to run getUserInfo if configured before we validate the claims.
+	// For token exchanges with access tokens, this is how we verify the token.
 	if c.getUserInfo {
 		userInfo, err := c.provider.UserInfo(ctx, oauth2.StaticTokenSource(token))
 		if err != nil {
diff --git a/connector/oidc/oidc_test.go b/connector/oidc/oidc_test.go
index 5c5208a60e7990310633da8d575916100349af82..29e8875ea760daff36d43b2da26a9a86dc1b1a1e 100644
--- a/connector/oidc/oidc_test.go
+++ b/connector/oidc/oidc_test.go
@@ -441,6 +441,7 @@ func TestTokenIdentity(t *testing.T) {
 		name        string
 		subjectType string
 		userInfo    bool
+		expectError bool
 	}{
 		{
 			name:        "id_token",
@@ -448,6 +449,7 @@ func TestTokenIdentity(t *testing.T) {
 		}, {
 			name:        "access_token",
 			subjectType: tokenTypeAccess,
+			expectError: true,
 		}, {
 			name:        "id_token with user info",
 			subjectType: tokenTypeID,
@@ -494,6 +496,9 @@ func TestTokenIdentity(t *testing.T) {
 			origToken := tokenResponse[long2short[tc.subjectType]].(string)
 			identity, err := conn.TokenIdentity(ctx, tc.subjectType, origToken)
 			if err != nil {
+				if tc.expectError {
+					return
+				}
 				t.Fatal("failed to get token identity", err)
 			}