In this section, we'll guide you through the process of authenticating a client with the Ember API using Callback Based Authorization or Nonce Based Authorization. Both methods are suitable for different use cases, so choose the one that best suits your needs. Callback Based Authorization is ideal for mobile and web applications, while Nonce Based Authorization is better suited for server-side applications, command-line interfaces, or any client that cannot handle callbacks.

Prerequisites

Before proceeding, ensure you have completed the following prerequisite:


Callback Based Authorization

Callback Based Authorization simplifies the authentication journey by redirecting users to a predetermined URL after they have authorized their account. This method enhances the user experience by providing a seamless and secure authentication flow.

Callback Based Authorization

Step 1: Generate a Callback URL

The initial step in this process involves generating a callback URL. This URL serves as a destination to which the user will be redirected after successfully authorizing their account. The callback URL must adhere to one of the following schemes:

  • exp://
  • ember://

For illustrative purposes, we'll use the Expo APIs to generate a callback URL. However, you're free to employ any method that produces a URL conforming to the above-mentioned schemes.

JavaScript

JavaScript

import * as Linking from "expo-linking"; // Creating a callback URLconst callback = Linking.createURL("authorize");

Step 2: Listen for the Authorization Token

Next, set up a listener for the authorization token. This token is transmitted to the callback URL as a query parameter named payload. The following example demonstrates how to listen for and retrieve the authorization token using the Expo APIs:

JavaScript

JavaScript

import * as Linking from "expo-linking"; // Setting up a listener for the callbackLinking.addEventListener("url", ({ url }) => {     // Parse the query parameters    const query = Object.fromEntries(url.split("?")[1].split("&").map(decodeURIComponent).map(part => part.split("=")))     // Securely store the authorization token and use it as the Bearer token for future API requests.    const token = query.payload; });

Step 3: Open the Authorization URL

The final step is to navigate to the authorization URL. This URL facilitates the authorization of the client with the user's account.

JavaScript

JavaScript

import base64 from "react-native-base64"; // Retrieve the HWID (see prerequisites)const device = base64.encode(JSON.stringify(hwid)); // Constructing the authorization URLconst url = new URL("/account/authorize", "https://www.embervpn.org"); // Appending the query parametersObject.entries({ callback, device })	.map(kv => kv.map(encodeURIComponent))	.forEach(([key, value]) => url.searchParams.append(key, value)); // Initiating the authorization processLinking.openURL(url.toString());

Upon the user's authorization of the client, they will be redirected to the callback URL. Subsequently, the event handler from Step 2 will activate, allowing us to extract the authorization payload from the query parameters.


Nonce Based Authorization

Nonce Based Authorization is an alternative method of authenticating with the Ember VPN API, particularly suitable for environments where callback-based methods are not practical. This method is ideal for server-side applications, command-line interfaces, or any client that cannot handle callbacks.

Nonce Based Authorization

Outline

  • To begin the authorization process, the client must first request a nonce from the Ember VPN API. This nonce is a one-time-use token that is valid for a limited time. The client must submit its HWID from the prerequisites to generate a nonce.

  • Next, the client opens an authorization URL in the user's browser. This URL facilitates the authorization of the client with the user's account. The client must append the nonce to the URL as a query parameter named nonce.

  • Check every few seconds to see if the user has authorized the nonce, and if so, retrieve the authorization token from the Ember VPN API. After retrieving the authorization token, nonce is destroyed and can no longer be used.

Step 1: Request a Nonce

The initial step in this process involves requesting a nonce from the Ember VPN API. This nonce is a one-time-use token that is valid for a 5 minutes. As an additional security measure, the nonce must be requested and accepted on the same IP address. The following example demonstrates how to request a nonce using the Ember VPN API:

JavaScript

JavaScript

// Retrieve the HWID (see prerequisites)const device = Buffer.from(JSON.stringify(hwid)).toString("base64"); // Fetch a nonce from the Ember VPN APIconst nonce = await fetch("https://www.embervpn.org/api/auth/session/nonce", {  method: "POST",  headers: { "Content-Type": "application/json" },  body: JSON.stringify({ device })}).then(res => res.json())  .then(res => res.nonce || null)  .catch(() => null);

Step 2: Open the Authorization URL

Next, open the authorization URL in the user's browser. This URL facilitates the authorization of the client with the user's account. The nonce must be appended to the URL as a query parameter named nonce.

JavaScript

JavaScript

// Constructing the authorization URLconst url = new URL("/account/authorize", "https://www.embervpn.org"); // Appending the nonceurl.searchParams.append("nonce", nonce); // Initiating the authorization processwindow.open(url.toString(), "_blank");

Step 3: Retrieve the Authorization Token

The final step is to retrieve the authorization token from the Ember VPN API. Since nonce auth is not a callback-based method, we must periodically check to see if the user has authorized the nonce. If the user has authorized the nonce, the Ember VPN API will return the authorization token. Otherwise, the API will return a 4xx error code. Once the authorization token has been retrieved, the nonce is destroyed and can no longer be used.

JavaScript

JavaScript

(async function loop() {	const token = await this.fetch("/api/auth/session/nonce", {	  method: "POST",	  body: JSON.stringify({ nonce })	}).catch(() => null)	  .then(resp => resp && Buffer.from(JSON.stringify(resp)).toString("base64")); 	// Check if the user has authorized the nonce	if(!token) return setTimeout(loop, 1000);			// Securely store the authorization token and use it as the Bearer token for future API requests.	const authorization = token; })();

Using the Authorization Token

Once you have obtained the authorization token, you can use it as the Bearer token for future API requests. The following example demonstrates how to use the authorization token to retrieve the user's account information:

JavaScript

JavaScript

// Fetch the user's account informationconst user = await fetch("https://www.embervpn.org/api/auth/session", {  method: "POST",  headers: { 	"Content-Type": "application/json",	"Authorization": `Bearer ${authorization}`  }, }).then(res => res.json())  .catch(() => null); // Log the user's account informationconsole.log("Welcome:", user.email);