The End of Life (EOL) date of Rules and Hooks will be November 18, 2026, and they are no longer available to new tenants created as of October 16, 2023. Existing tenants with active Hooks will retain Hooks product access through end of life.We highly recommend that you use Actions to extend Auth0. With Actions, you have access to rich type information, inline documentation, and public npm packages, and can connect external integrations that enhance your overall extensibility experience. To learn more about what Actions offer, read Understand How Auth0 Actions Work.To help with your migration, we offer guides that will help you migrate from Rules to Actions and migrate from Hooks to Actions. We also have a dedicated Move to Actions page that highlights feature comparisons, an Actions demo, and other resources to help you on your migration journey.To read more about the Rules and Hooks deprecation, read our blog post: Preparing for Rules and Hooks End of Life.
At the Client Credentials Exchange extensibility point, Hooks let you execute custom actions when an is issued through the Authentication API POST /oauth/token endpoint using the Client Credentials Flow. For example, you may deny the token from being issued, add custom claims to the access token, or modify its scopes. To learn more, read Client Credentials Flow.Hooks at this extensibility point are blocking (synchronous), which means they execute as part of the trigger’s process and prevent the rest of the Auth0 pipeline from running until the Hook is complete.
The triggerId for the Client Credentials Exchange extensibility point is credentials-exchange. To learn how to create hooks for this extensibility point, read Create Hooks.
To learn about other extensibility points, read Extensibility Points.
When creating a Hook executed at the Client Credentials Exchange extensibility point, you may find the following starter code helpful. Parameters that can be passed into and used by the Hook function are listed at the top of the code sample.
Copy
Ask AI
/**@param {object} client - client information@param {string} client.name - client name@param {string} client.id - client ID@param {string} client.tenant - Auth0 tenant name@param {object} client.metadata - client metadata@param {array|undefined} scope - either an array of strings representing the token's scope claim, or undefined@param {string} audience - token's audience claim@param {object} context - Auth0 context info@param {object} context.webtask - Hook (webtask) context@param {function} cb - function (error, accessTokenClaims)*/module.exports = function(client, scope, audience, context, cb) { var access_token = {}; access_token.scope = scope; // do not remove this line // Modify scopes or add extra claims // access_token['https://example.com/claim'] = 'bar'; // access_token.scope.push('extra'); // Deny the token and respond with an OAuth2 error response // if (denyExchange) { // // To return an HTTP 400 with { "error": "invalid_scope", "error_description": "Not authorized for this scope." } // return cb(new InvalidScopeError('Not authorized for this scope.')); // // // To return an HTTP 400 with { "error": "invalid_request", "error_description": "Not a valid request." } // return cb(new InvalidRequestError('Not a valid request.')); // // // To return an HTTP 500 with { "error": "server_error", "error_description": "A server error occurred." } // return cb(new ServerError('A server error occurred.')); // } cb(null, access_token);};
Please note:
The callback function (cb) at the end of the sample code signals completion and must be included.
The line access_token.scope = scope ensures that all granted scopes will be present in the access token. Removing it will reset all scopes, and the token will include only scopes you add with the script.
Once you’ve customized the starter code with your scopes and additional claims, you can test the Hook using the runner embedded in the Hook Editor. The runner simulates a call to the Hook with the same body and response that you would get with a Client Credentials Exchange.
Executing the code using the runner requires a save, which means that the original code will be overwritten.
When you run a Hook based on the starter code, the response object is:
Sample script: Add an additional scope to the access token
In this example, we use a Hook to add an additional scope to those already existing for the access token.
Copy
Ask AI
module.exports = function(client, scope, audience, context, cb) { // Scopes to be added var access_token = {}; // Get the scope that's currently on the Access Token // and add it to the object we're working with // Do not remove this line! access_token.scope = scope; // Append the `read:resource` scope access_token.scope.push('read:resource'); // Callback to indicate completion and to return new // array of scopes cb(null, access_token);};
In this example, we add a namespaced custom claim and its value to the access token. To learn more, read Create Namespaced Custom Claims.You can add the following as claims to the issued token:
The scope property of the response object
Any properties with namespaced property names
The extensibility point ignores all other response object properties.
To access a configured Hook Secret from within a hook, use context.webtask.secrets.SECRET_NAME.
Copy
Ask AI
module.exports = function(client, scope, audience, context, cb) { // Claims to be added var access_token = {}; // New claim to add to the token access_token['https://example.com/foo'] = 'bar'; // Callback to indicate completion and to return new claim cb(null, access_token); };
Sample script: Raise an error or deny an access token
In this example, we use custom Error objects to generate OAuth2 Error Responses. (To learn more, see OAuth2 RFC - Section 5.2 in the IETF Datatracker.)If a plain JavaScript error is returned in the callback, such as:
Copy
Ask AI
module.exports = function(client, scope, audience, context, cb) { // Callback to indicate completion and to return new claim cb(new Error("Unknown error occurred."); };
Then when you request a client_credentials grant from the /oauth/token endpoint, Auth0 will respond with:
Currently, the behavior of the built-in JavaScript Error class and ServerError is identical, but the ServerError class allows you to be explicit about the OAuth2 error that will be returned.