Self-Service Machine-to-Machine

If your business case services a non-interactive audience, like APIs or backend servers, you will onboard with a machine-to-machine (M2M) configuration.

Use cases

Use the M2M onboarding path if you:

  • Support service-to-service communications

  • Have scheduled jobs or cron tasks running on servers that need to access protected resources or APIs

  • Allow IoT devices to communicate with backend services or APIs

  • Have an API layer that needs to communicate with other API layers without user involvement or after a user token has expired

  • Have a privileged API that may need to be called before a user has authenticated (i.e. from an Action or custom database script in your Auth0 tenant)

  • Use an API Gateway to manage backend services

  • Use or support non-interactive applications or other tooling not involving human interaction such as daemons or backend services

How to use this guide

This guide is a pathway to create your M2M implementation in Auth0. We provide considerations, best practices, and concepts you should review.

  • In Architecture, we advise you to configure Auth0 to support your Software Development Life Cycle and existing infrastructure.

  • In Create an account, we provide instructions to create your API instance in Auth0 and an application to support the authentication flow (or grant) needed for machine-to-machine authentication.

  • In Authentication, we walk through the grant you need to use for authentication as well as access tokens and permissions (or scopes) you can set.

  • In Branding, we advise you where to find information on how to configure Custom Domains depending on how you plan to manage certificates.

  • In Deployment Automations, you can read about our tooling to assist with deployment.

  • In Quality Assurance, you can learn more about unit testing, and the readiness checks we provide in Auth0 Dashboard.

Architecture

Before you configure your Auth0 account and tenant, or the groups and structures of your Auth0 services, create a map of your existing infrastructure so you can best leverage Auth0’s capabilities in your existing ecosystem.

As mentioned in common scenarios, you may have other non-interactive technologies in your application domain, network domain, or M2M device domain to consider before you configure Auth0. To review an example M2M scenario, read Server + API. To attempt a hands-on lab working with Node and test API deployment, visit our GitHub repository.

You may want to create a visualization of your current tech stack as well as plan how Auth0 fits in with your current Software Development Lifecycle (SDLC). This can help you determine how many tenants you may need.

Considerations

Before you create a new account or configure your first tenant, you may want to consider:

  • How you partition or group your APIs to call specific endpoints. 

    • This may determine the audience and other claims on access tokens.

  • Any third-party consumers to your resource may request an access token for each call. Excessive calls could affect your rate limit.

Create an account

Now that you have a plan for your architecture, you’ll configure your Auth0 account and tenants. When you sign up for Auth0 services, you will create your first tenant. This is where you configure Auth0 assets, services, and resources. Sign up to start.

Before you start

In the Auth0 Dashboard or with the Auth0 Management API, create: 

  • An API to represent your API

  • An M2M application to use the Client Credential Flow 

You may want to plan some configuration details before you create an account.

  • Your tenant name has a role in your Auth0 domain. Before you determine a name, you should review tenant characteristics.

  • Which Auth0 features you need for your use case. Some features are only available on Professional and Enterprise plans.

  • Determine if you need to support multiple environments, such as development, staging, and production. To learn more, read Set Up Multiple Environments.

  • If you have a use case involving thirty-party applications you want to register in a tenant, you can use Dynamic Application Registration based on the OIDC Client Registration specification.

Provision a tenant

Now that you have a plan for your architecture, you’ll configure your Auth0 account and Tenant.

Register an API

In this section, create your API in Auth0.

Start by creating an instance in the Auth0 Dashboard for your APIs.

  1. Follow instructions to register your API.

In the Authentication section, configure your API settings for M2M authentication.

Associate an application

You need to create an association between your application and your API so your application can request access tokens from it. You will learn more about client grants in the Authentication section.

If you create your API in the Dashboard, Auth0 automatically generates a test application and associates it with your API.

  1. Navigate to Auth0 Dashboard > Applications.

  2. Select the test M2M test application created when you created your API.

  3. Switch to the API view, and then locate the API you’d like to enable for this application.

  4. Enable the Authorize toggle, and then select the arrow button on the right to expand the card.

  5. Select Update.

    Dashboard > Applications > APIs

Authentication

When calling one API from another API, or from any situation where there is no authenticated user context, you need a way to authorize the application instead of a user. This is a one step process where the application is authenticated (using a client_id and client_secret) and then authorized in one call.

For non-interactive applications or services to authentication, you must select a client grant, or authentication flow. The OAuth 2.0 Client Credentials Flow does not require human interaction and is best suited for M2M applications.

Before you start

In Auth0 Dashboard or Management API, you will: 

  • Set your application to use the Client Credentials Flow

  • Update the scopes for your M2M access tokens

Before you configure your authentication method:

  • Review the Client Credentials Flow for machine-to-machine authentication. This is the workflow for non-interactive authentication and authorization.

  • Determine the level of access for your APIs. This helps determine what scopes, or permissions, you will configure when you create your API.

Configure the Client Credential Flow

You can use the Auth0 Dashboard or Management API to set the authentication flow to provide a client credential in exchange for an access token.

Follow the instructions on Update Grant Types to use Auth0 Dashboard or Management API.

M2M access tokens

In token-based authentication, non-interactive clients provide client_id and client_secret in a call to the Authentication API token endpoint to get an access token. This access token permits access to your protected API.

The default profile, or format, is the Auth0 token profile associated with two token profiles. You can choose to change the token profile to RFC 9068. To learn more, read Access Token Profiles. To verify the token is valid, your API will check the Signing Algorithms. The default signing algorithm is RSA256, a key-based algorithm.

Example

A request to the /oauth/token endpoint should be similar to the sample below:


curl --request POST \
  --url 'https://{yourDomain}/oauth/token' \
  --header 'content-type: application/x-www-form-urlencoded' \
  --data grant_type=client_credentials \
  --data client_id=YOUR_CLIENT_ID \
  --data client_secret=YOUR_CLIENT_SECRET \
  --data audience=YOUR_API_IDENTIFIER

Was this helpful?

/
var client = new RestClient("https://{yourDomain}/oauth/token");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddParameter("application/x-www-form-urlencoded", "grant_type=client_credentials&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&audience=YOUR_API_IDENTIFIER", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);

Was this helpful?

/
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io/ioutil"
)

func main() {

	url := "https://{yourDomain}/oauth/token"

	payload := strings.NewReader("grant_type=client_credentials&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&audience=YOUR_API_IDENTIFIER")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("content-type", "application/x-www-form-urlencoded")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}

Was this helpful?

/
HttpResponse<String> response = Unirest.post("https://{yourDomain}/oauth/token")
  .header("content-type", "application/x-www-form-urlencoded")
  .body("grant_type=client_credentials&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&audience=YOUR_API_IDENTIFIER")
  .asString();

Was this helpful?

/
var axios = require("axios").default;

var options = {
  method: 'POST',
  url: 'https://{yourDomain}/oauth/token',
  headers: {'content-type': 'application/x-www-form-urlencoded'},
  data: new URLSearchParams({
    grant_type: 'client_credentials',
    client_id: 'YOUR_CLIENT_ID',
    client_secret: 'YOUR_CLIENT_SECRET',
    audience: 'YOUR_API_IDENTIFIER'
  })
};

axios.request(options).then(function (response) {
  console.log(response.data);
}).catch(function (error) {
  console.error(error);
});

Was this helpful?

/
#import <Foundation/Foundation.h>

NSDictionary *headers = @{ @"content-type": @"application/x-www-form-urlencoded" };

NSMutableData *postData = [[NSMutableData alloc] initWithData:[@"grant_type=client_credentials" dataUsingEncoding:NSUTF8StringEncoding]];
[postData appendData:[@"&client_id=YOUR_CLIENT_ID" dataUsingEncoding:NSUTF8StringEncoding]];
[postData appendData:[@"&client_secret=YOUR_CLIENT_SECRET" dataUsingEncoding:NSUTF8StringEncoding]];
[postData appendData:[@"&audience=YOUR_API_IDENTIFIER" dataUsingEncoding:NSUTF8StringEncoding]];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://{yourDomain}/oauth/token"]
                                                       cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                   timeoutInterval:10.0];
[request setHTTPMethod:@"POST"];
[request setAllHTTPHeaderFields:headers];
[request setHTTPBody:postData];

NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                if (error) {
                                                    NSLog(@"%@", error);
                                                } else {
                                                    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
                                                    NSLog(@"%@", httpResponse);
                                                }
                                            }];
[dataTask resume];

Was this helpful?

/
$curl = curl_init();

curl_setopt_array($curl, [
  CURLOPT_URL => "https://{yourDomain}/oauth/token",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => "grant_type=client_credentials&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&audience=YOUR_API_IDENTIFIER",
  CURLOPT_HTTPHEADER => [
    "content-type: application/x-www-form-urlencoded"
  ],
]);

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}

Was this helpful?

/
import http.client

conn = http.client.HTTPSConnection("")

payload = "grant_type=client_credentials&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&audience=YOUR_API_IDENTIFIER"

headers = { 'content-type': "application/x-www-form-urlencoded" }

conn.request("POST", "/{yourDomain}/oauth/token", payload, headers)

res = conn.getresponse()
data = res.read()

print(data.decode("utf-8"))

Was this helpful?

/
require 'uri'
require 'net/http'
require 'openssl'

url = URI("https://{yourDomain}/oauth/token")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

request = Net::HTTP::Post.new(url)
request["content-type"] = 'application/x-www-form-urlencoded'
request.body = "grant_type=client_credentials&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&audience=YOUR_API_IDENTIFIER"

response = http.request(request)
puts response.read_body

Was this helpful?

/
import Foundation

let headers = ["content-type": "application/x-www-form-urlencoded"]

let postData = NSMutableData(data: "grant_type=client_credentials".data(using: String.Encoding.utf8)!)
postData.append("&client_id=YOUR_CLIENT_ID".data(using: String.Encoding.utf8)!)
postData.append("&client_secret=YOUR_CLIENT_SECRET".data(using: String.Encoding.utf8)!)
postData.append("&audience=YOUR_API_IDENTIFIER".data(using: String.Encoding.utf8)!)

let request = NSMutableURLRequest(url: NSURL(string: "https://{yourDomain}/oauth/token")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()

Was this helpful?

/

The response should be similar to the sample below:

HTTP/1.1 200 OK
Content-Type: application/json
{
  "access_token":"eyJz93a...k4laUWw",
  "token_type":"Bearer",
  "expires_in":86400
}

Was this helpful?

/

Token expiration

Your access tokens have a limit for how long the token is valid. Since your communications are on the back-channel, you cannot use refresh tokens to extend sessions, and should consider configuring your access tokens with a 1-hour expiration time. You may need to strike your own balance between security and performance for your specific environment. To learn more, read Update Access Token Lifetime.

Scopes

Before any non-interactive clients or services call your API, you need to define the permissions or Scopes your API allows. You can set the scopes in Auth0 Dashboard to include in your authentication request to Authentication API. To read more examples of ways to use API scopes, read API Scopes.

To configure scopes, follow the instructions on Add API Permissions for Auth0 Dashboard or use the sample provided for Management API.

Branding

Even if you service non-interactive clients or services working on the back-channel, you can still customize your experience to align with the look and feel of your existing brand.

Custom domains

Auth0 supports the use of custom domains when you call the /authorize endpoint to request access tokens.

M2M Onboarding - custom domains

In Auth0 Dashboard, you must:

  • Register and verify your domain before you can use it with your Auth0 services.

  • Determine if you want to manage your own certificate or use an Auth0 managed certificate. To learn more about certificates, read Certificate management options.

  • Verify the TLS (SSL) version and cipher you want to use for self-managed certificates is supported by Auth0. To learn more, read TLS (SSL) Versions and Ciphers.

  1. To configure your custom domain with Auth0-managed certificates, follow the instructions on Configure Custom Domains with Auth0-Managed Certificates.

    1. If you want to manage your own certificates, follow the instructions on Configure Custom Domains with Self-Managed Certificates.

  2. Review API configuration with custom domains. You may need to adjust your API settings to incorporate a custom domain.

If you experience issues with your custom domain, review Troubleshoot Custom Domains.

Deployment Automation

Auth0 provides support for a couple of different options when it comes to the deployment automation approaches you can use, and each can be used in conjunction with the other.

Best Practice

However you configure deployment automation, we’d recommend you unit test your custom code and Actions prior to deployment, and run some integration tests against your tenant post-deployment too.

Deploy CLI Tool

As recommended under the Architecture section, you should have Auth0 tenants for development, test, and production. These tenants should share identical configurations for quality checks and testing; however, you may be faced with errors as a result of mismatched configurations between your environments. For example, each environment will have different Client IDs and Client Secrets.

To mitigate these mismatch errors, you can use the Deploy CLI Tool to help you integrate your Auth0 instance with your existing CI/CD pipeline.  With dynamic keyword replacement, you can replace environmental variables on tenants sharing similar configurations. To learn more, read Deploy CLI Tool and Keyword Replacement.

Real-time Webtask Logs Extension

The Real-time Webtask Logs extension displays all logs for custom code in real-time, including console.log output and other exceptions. If you are using Auth0 Actions or other custom logic, you can use this extension to debug and troubleshoot. To learn more about installation and configuration, read Real-time Webtask Logs Extension.

Quality Assurance

Quality Assurance is important in identifying issues before you go live. Depending on the nature of your project, there are several different types of quality assurance testing that you’re going to want to consider as part of your integration with Auth0:

  • How will your APIs perform when subjected to unexpected production loads?

  • How will your rate limits be affected by third-party applications?

If you are not using Auth0 widgets or features, like Universal Login, you will not have the built-in usability and accessibility best practices out-of-the-box on a host of browsers and devices. To ensure functional requirements are met and unexpected events are handled correctly, guidance is provided for testing the integration between your application(s) and Auth0, and for unit testing individual extensibility modules, such as Auth0 Actions. We also recommend you review Auth0’s penetration testing policy and complete Mock testing you can leverage in conjunction with our load testing policy to help ensure your application(s) perform under unexpected load.

Unit testing

Unit testing is verifying units of extensibility, like Auth0 Actions. If you are using custom code we recommend using a test framework (such as Mocha) to test the additional code before deployment.

Mock testing

In a balance between Auth0’s load testing policy and the desire to load test, it is common practice to create a mock test of Auth0’s endpoints. This is a valuable practice in order to ensure that your configuration works with your expected interfaces without having to restrict your testing, and tools such as MockServer, JSON Server, or even Postman can be used to assist.

Deployment

Our Deploy and Monitor section provides guidance for deployment best practices. We advise your review Pre-Deployment Checks, especially the built-in Auth0 Dashboard Readiness Checks.

To review the Readiness Check, select the drop-down menu below your tenant name and environmental tag at Auth0 Dashboard > Run Readiness Checks.

Auth0 Dashboard > Readiness Checklist

You can use the filter to apply the Readiness Checks to selected applications. These checks do not apply to your configured APIs.

For checks that do not apply to your specific configuration, you can select Dismiss to remove them from the final results.

We advise you to review Deployment Best Practices for final checks before you go live and take advantage of Logs to monitor your services.

Learn more