@@ -57,6 +57,8 @@ public class AuthAPI {
5757 private static final String KEY_MFA_TOKEN = "mfa_token" ;
5858 private static final String KEY_CLIENT_ASSERTION = "client_assertion" ;
5959 private static final String KEY_CLIENT_ASSERTION_TYPE = "client_assertion_type" ;
60+ private static final String KEY_SUBJECT_TOKEN = "subject_token" ;
61+ private static final String KEY_SUBJECT_TOKEN_TYPE = "subject_token_type" ;
6062 private static final String PATH_OAUTH = "oauth" ;
6163 private static final String PATH_TOKEN = "token" ;
6264 private static final String PATH_DBCONNECTIONS = "dbconnections" ;
@@ -800,6 +802,44 @@ public TokenRequest requestToken(String audience, String org) {
800802 return request ;
801803 }
802804
805+ /**
806+ * Creates a request to exchange an external subject token for Auth0 tokens using the
807+ * {@code urn:ietf:params:oauth:grant-type:token-exchange} grant (Custom Token Exchange).
808+ * A Token Exchange Profile that maps the given {@code subjectTokenType} must be configured on the tenant, and
809+ * client authentication (client secret or client assertion) is required.
810+ * <pre>
811+ * {@code
812+ * try {
813+ * TokenHolder result = authAPI.exchangeToken("test-user123-john@example.com", "urn:mycompany:m2m-test-token")
814+ * .setAudience("https://myapi.me.auth0.com/users")
815+ * .setScope("openid profile email")
816+ * .execute()
817+ * .getBody();
818+ * } catch (Auth0Exception e) {
819+ * //Something happened
820+ * }
821+ * }
822+ * </pre>
823+ *
824+ * @see <a href="https://auth0.com/docs/authenticate/custom-token-exchange">Custom Token Exchange documentation</a>
825+ * @param subjectToken the external token representing the identity of the subject. Must not be null.
826+ * @param subjectTokenType an identifier for the type of the {@code subjectToken}, matching a configured Token
827+ * Exchange Profile (for example {@code urn:mycompany:m2m-test-token}). Must not be null.
828+ * @return a Request to configure and execute.
829+ */
830+ public TokenRequest exchangeToken (String subjectToken , String subjectTokenType ) {
831+ Asserts .assertNotNull (subjectToken , "subject token" );
832+ Asserts .assertNotNull (subjectTokenType , "subject token type" );
833+
834+ TokenRequest request = new TokenRequest (client , getTokenUrl ());
835+ request .addParameter (KEY_CLIENT_ID , clientId );
836+ request .addParameter (KEY_GRANT_TYPE , "urn:ietf:params:oauth:grant-type:token-exchange" );
837+ request .addParameter (KEY_SUBJECT_TOKEN , subjectToken );
838+ request .addParameter (KEY_SUBJECT_TOKEN_TYPE , subjectTokenType );
839+ addClientAuthentication (request , true );
840+ return request ;
841+ }
842+
803843 /**
804844 * Creates a request to revoke an existing Refresh Token.
805845 * Confidential clients (Regular Web Apps) <strong>must</strong> have a client secret configured on this {@code AuthAPI} instance.
0 commit comments