Authentication
There are two different types of authentication for the Light APIs. Both types utilize tokens passed as Bearer
tokens in the Authorization
header of HTTP requests. For example:
curl --request GET --url https://api.light.dev/v1/app/accounts \
--header 'Authorization: Bearer YOUR_TOKEN'
App Tokens vs Account Tokens
The first type of auth token is an AppToken
, which is a long-lived token that is generated per-application that you build on Light. These tokens can be used for privileged APIs such as creating new Account
s for your App
, edit sensitive details about those accounts such as their verified email address, and generating AccountToken
s to interact further with the accounts. AppToken
s should be kept secret and only used from a secure environment like your backend server.
The second type of token is an AccountToken
. These are tokens that you generate using your AppToken
for a specific account (i.e. user of your App
). AccountToken
s are not long-lived and will expire after 60 minutes (or at the expires_at
timestamp given in the POST /app/accounts/{uuid}/token
API response). These tokens can only access information or affect a single user account of your app and can be used either from a backend server or a frontend client. AccountTokens
can be used from a frontend client to speed up and simplify your integration by avoiding proxying all requests through your server. However, you can use these from your server if you prefer.
Using Account Tokens
In order to use AccountToken
s from your frontend client, you will need to provide a way for your client to fetch a new AccountToken
periodically as it expires. We would recommend a pattern similar to the following, where you can serve a Light AccountToken
for a given user on your platform via API.
1. Backend API to generate Account Tokens
@api.post("/energy/token")
def get_energy_token(request):
# Save a Light account UUID to your user model once you have created
# a Light account for the user.
light_account_uuid = request.user.light_account_uuid
if light_account_uuid is None:
raise Exception("Light account not created")
# Cache the per-account tokens since they are valid for 1 hour
cache_key = f"energy-token-{light_account_uuid}"
token = cache.get(cache_key)
if token:
return token
api = LightServerAPI()
# POST /app/accounts/{light_account_uuid}/token
response = api.create_energy_token(light_account_uuid)
cache.set(cache_key, response, 50 * 60) # cache for 50 minutes
return response
2. Frontend client to use Account Tokens
Your front-end would then call the above /energy/token
endpoint that you implemented and then use the resulting Account Token for calling Light API endpoints. You may want to cache Account Tokens on the client to avoid having to call your /energy/token
endpoint before each client-side call to the Light API. For example, in JavaScript you could have an API helper like this:
const energyToken = {
token: null,
expiry: null,
};
// Function to get the cached token if it exists and is not expired
function getCachedToken() {
const { token, expiry } = energyToken;
return token && expiry && new Date() < new Date(expiry) ? token : null;
}
// Function to fetch a new token from the backend
async function fetchToken() {
const response = await fetch("/energy/token", {
method: "POST",
credentials: "include",
});
if (!response.ok) throw new Error("Failed to fetch token");
const { token, expires_at } = await response.json();
// cache the token and expiration date
energyToken.token = token;
energyToken.expiry = expires_at;
return token;
}
// Function to get the token, using cache if available
export async function getToken() {
return getCachedToken() || fetchToken();
}
3. Example client usage
You can then use the above helper in your frontend API calls like this:
import { getToken } from "./api";
// Example function to perform an API request using the account token
async function fetchAccountData() {
const token = await getToken();
const response = await fetch("https://api.light.dev/v1/account", {
method: "GET",
headers: { Authorization: `Bearer ${token}` },
});
if (!response.ok) throw new Error("Failed to fetch account data");
const data = await response.json();
console.log("Account data:", data);
}