---
schema_version: "1"
id: 53fc38c76f999b97b359d8716713e5f541884abb0a3f137e4ac8bae94344dc4a
title: Create a Token Exchange Handler Apex Class
collection: admin
version: current
locale: en-us
portal_url: https://docs.salesforce.com/admin/current/en-us/xcloud/264-0-0/remoteaccess_token_exchange_create_apex.md
canonical_url: https://help.salesforce.com/s/articleView?id=xcloud.remoteaccess_token_exchange_create_apex.htm&release=264.0.0&type=5
source_site: help.salesforce.com
content_type: documentation
content_hash: 80da6a8b9255cc0345e4e5f7f06909baab3fc209fd8bd7cbdfdb6aa06202427f
description: A token exchange handler consists of an Apex class that extends the Oauth2TokenExchangeHandler abstract class and a token exchange handler definition. To get started, create an Apex class to reference in the handler definition.
products:
  - Security
  - Cross Cloud
release: "264"
---
# Create a Token Exchange Handler Apex Class

A token exchange handler consists of an Apex class that extends the `Oauth2TokenExchangeHandler` abstract class and a token exchange handler definition. To get started, create an Apex class to reference in the handler definition.

### Required Editions

<table class="slds-table slds-table_bordered slds-max-medium-table_stacked slds-m-bottom_small edition"><colgroup><col></colgroup><tbody><tr class=""><td class="slds-cell-wrap" style="vertical-align:top;">Available in: <strong>Enterprise</strong>, <strong>Performance</strong>, <strong>Unlimited</strong>, and <strong>Developer</strong> Editions</td></tr></tbody></table>

![Note](https://sf-zdocs-cdn-prod.zoominsoftware.com/tdta-xcloud-identity-264-0-0-production-enus/699dab6f-8f1a-4662-b24f-6521d5b747f7/images/icon_note.png)

Note You can skip this step by autogenerating an Apex class template when you [define a handler in Setup](https://help.salesforce.com/s/articleView?id=xcloud.remoteaccess_token_exchange_handler_define.htm&type=5&language=en_US). Make sure you customize the autogenerated handler.

1. From Setup, in the Quick Find box, enter Apex, and then select **Apex Classes**.
2. Click **New**.
3. Create an Apex class that extends the `Auth.Oauth2TokenExchangeHandler` abstract class.
    
    Here’s what the abstract class looks like. It contains two methods. Use the first method to validate the incoming token from the identity provider. Use the second method to map the subject of the token to a Salesforce user.
    
    ```java
    //Abstract Class that a developer must extend for a token exchange handler
    global abstract class Oauth2TokenExchangeHandler {
    
        //First method called in the handler
        //This method must be overriden by the extending class 
        global virtual Auth.TokenValidationResult validateIncomingToken(String appDeveloperName, Auth.IntegratingAppType appType, String incomingToken, Auth.OAuth2TokenExchangeType tokenType)  
            return null;
        }
        
        //Second method called in the handler
        //This method must be overriden by the extending class 
        global virtual User getUserForTokenSubject(Id networkId, Auth.TokenValidationResult result, Boolean canCreateUser, String appDeveloperName, Auth.IntegratingAppType appType) {
            return null;
        }
    }
    ```
    
    Here’s an example implementation that extends the `Auth.Oauth2TokenExchangeHandler` abstract class.
    
    ![Important](https://sf-zdocs-cdn-prod.zoominsoftware.com/tdta-xcloud-identity-264-0-0-production-enus/699dab6f-8f1a-4662-b24f-6521d5b747f7/images/icon_important.png)
    
    Important This code sample is for demonstration only. Use it as a starting point, but make sure you evaluate, customize, and test it carefully.
    
    ```java
    /*Token Exchange Handler Implementation Example*/
    public class MyTokenExchangeClass extends Auth.Oauth2TokenExchangeHandler{
        
        public override Auth.TokenValidationResult validateIncomingToken(String appDeveloperName, Auth.IntegratingAppType appType, String incomingToken, Auth.OAuth2TokenExchangeType tokenType) {
            //Depending on your incoming token, you validate it in different ways
            //If the incoming token is an opaque access token or refresh token, validate it with a callout to the identity provider
            //If it is a SAML assertion, validate it by checking the XML
            //If it is an ID Token or JWT, try using our JWT validation methods
            //The example below assumes that the incoming token is a JWT and that there is a public keys endpoint on the identity provider
            //Be very careful with any logic in this method and test carefully before using 
            
            Boolean isValid = false;
            Auth.JWT jwt; 
            //Custom data structure 
            CustomStructuredUserData customData;
            //Standard user data structure
            Auth.UserData userData; 
            
            if (tokenType == Auth.OAuth2TokenExchangeType.JWT || tokenType == Auth.OAuth2TokenExchangeType.ID_TOKEN) {
                try {
                    jwt = Auth.JWTUtil.validateJWTWithKeysEndpoint(incomingToken, 'https://your-idp.com/keys', true); 
                    isValid = true; 
                    //These values would be sourced from the JWT or ID Token
                    userData = new Auth.UserData('identifier', 'firstName', 'lastName', 'fullName', 'customer@email.com', 'link url', 'remote username', 'local', 'Provider (IDP Name)', '', new Map<String,String>());
                    //You can also pass data as generic object
                    customData = new CustomStructuredUserData();
                } catch (Exception e) {
                    isValid = false; 
                }
            } else if (tokenType == Auth.OAuth2TokenExchangeType.ACCESS_TOKEN || tokenType == Auth.OAuth2TokenExchangeType.REFRESH_TOKEN) {
                //Logic for validating a opaque access token or refresh token can go here
                //This validation typically involves a callout to the introspect or user info endpoints
                //If you call out to the user info endpoint, make sure to pass the data from the validation into the getUserForTokenSubject method using an Apex class or the user data class
                isValid = false;
            } else if (tokenType == Auth.OAuth2TokenExchangeType.SAML_2) {
                //Logic for validating a SAML assertion can go here
                //This validation involves XML parsing
                isValid = false;
            } else {
                //You can add new token types. If you don’t know how to validate the token, always check the type and return false
                isValid = false;
            }
            
                  
            if(isValid){
                return new Auth.TokenValidationResult(true, (object)customData, userData, incomingToken, tokenType, 'CustomErrorMessage');
            } else {
                return new Auth.TokenValidationResult(isValid);
            }       
        }
        
        public override User getUserForTokenSubject(Id networkId, Auth.TokenValidationResult result, Boolean canCreateUser, String appDeveloperName, Auth.IntegratingAppType appType) {
            //If you passed data from the validation method, grab it now. Remember to cast back for the custom data
            CustomStructuredUserData customData = (CustomStructuredUserData)result.data;
            Auth.UserData userData = result.userData; 
            
            //If you don’t have any data from the token, you can perform a callout using the incoming token
            String userToken = result.token;
            
            //Now, search for a user
            User u; 
            try {
                u = [SELECT Id, IsActive FROM User WHERE email =: userData.email];
            } catch (Exception e) {
                //No user existed for this email address, or there were too many. Try looking harder
            }
            
            // If you didn’t find a user, check to see if you can create one
            if (canCreateUser && (u == null)) {
                u = new User(); 
                u.firstName = userData.firstName; 
                u.lastName = userData.lastName; 
                //... Finish setting user attributes. For external users, make sure you set up the contact/account/person account
                //If you assign permission sets, do it in a future method to avoid mixed DML
                //Returning the user from this method handles the insertion, so it’s not necessary to manually insert
            }
            
            return u;
        }
        
        //This class gives you a way to pass stuctured data between the validateIncomingToken and getUserForTokenSubject methods
        //This example is for demonstration only. Implement this class in a way that matches the data that you are passing
        private class CustomStructuredUserData {
            public String customAttribute1;
            public Integer customAttribute2;
            public Map<String,Object> customAttribute3;   
        }
    }
    ```
4. Save the class.
5. When you’re ready, customize the class’s validation and subject mapping methods. Depending on your development process, you can complete this step after you finish creating the handler.

To finish creating the handler, [define a token exchange handler](https://help.salesforce.com/s/articleView?id=xcloud.remoteaccess_token_exchange_handler_define.htm&type=5&language=en_US). You can define the handler in Setup or use Metadata API.

For more information about customizing your Apex handler, see these resources.

- Apex Developer Guide: [OAuth 2.0 Token Exchange Handler Examples](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/token_exchange_handler.htm)
- Apex Reference Guide: [Oauth2TokenExchangeHandler Class](https://developer.salesforce.com/docs/atlas.en-us.apexref.meta/apexref/apex_class_Auth_Oauth2TokenExchangeHandler.htm)
- Apex Reference Guide: [TokenValidationResult Class](https://developer.salesforce.com/docs/atlas.en-us.apexref.meta/apexref/apex_class_Auth_TokenValidationResult.htm)
- Apex Reference Guide: [JWTUtil Class](https://developer.salesforce.com/docs/atlas.en-us.apexref.meta/apexref/apex_class_Auth_JWTUtil.htm)
- Apex Reference Guide: [OAuth2TokenExchangeType Enum](https://developer.salesforce.com/docs/atlas.en-us.apexref.meta/apexref/apex_enum_Auth_OAuth2TokenExchangeType.htm)
- Apex Reference Guide: [IntegratingAppType Enum](https://developer.salesforce.com/docs/atlas.en-us.apexref.meta/apexref/apex_enum_Auth_IntegratingAppType.htm)