Authentication
All communication between your application and Weavy environment goes through the Web API and needs to be properly authenticated.
Authentication is done with Bearer authentication over HTTPS (SSL), and this article explains how to acquire tokens for different scenarios such as server-to-server and user-to-server (including how to configure authentication when adding Weavy building blocks to your application).
Finally, we present some best practices for how to use and manage tokens.
Server authentication
Tokens used in server-to-server communication are called API keys
and can be generated from your the environment page on your Weavy account.
An API key does not associate your request with a user account. Instead, permissions are evaluated in the sudo
context which gives your app the powers of a "super user".
It is therefore very important that the you store the token securely and never expose it in client side code or similar.
While API keys can be configured to never expire, we strongly recommend that you set an expiration date to prevent potential security issues.
User authentication
When your application acts on behalf of a user, it performs a user-to-server request. These requests must contain an access_token
for the user in the Authorization
header to associate the request with the authenticated user.
Example: Get user information for the authenticated user.
curl https://{WEAVY-SERVER}/api/user
-H "Authorization: Bearer {ACCESS-TOKEN}"
To obtain an access_token
you make a server-to-server request from your server to the tokens endpoint in your Weavy environment (by default access tokens expire after 3600
seconds, but you can specify a custom lifetime with the expires_in
parameter when issuing the token).
Example: Issue an access token for user with uid
u256.
curl -X POST https://{WEAVY-SERVER}/api/users/u256/tokens
-H "Authorization: Bearer {API-KEY}"
Single Sign-On
Our building blocks have built-in functionality for Single Sign-On (SSO) and seamless authentication between your app and Weavy.
All you need to do is provide a token endpoint and configure the tokenUrl
property.
The workflow for authentication then becomes:
- When the building block needs to perform an API request to the Weavy environment it will ask your backend to supply an
access_token
for the authenticated user by calling the token endpoint configured by thetokenUrl
property. - Your backend will check if it already has an
access_token
for the user, and if one exists send it back. - If no token exists (or the token has expired) your backend makes a request to the Weavy environment for a new access token.
- Weavy returns an
access_token
for the user (to improve response times and reduce roundtrips, it is good practice to store and reuse it as per step 2). - Your backend returns a JSON response with the
access_token
to the building block.
Token endpoint
As stated above, you are responsible for supplying an access_token
to the building blocks when required.
This is usually done by configuring Weavy with a tokenUrl
property that points to an endpoint that returns a JSON document with an access_token
for the authenticated user.
{
"access_token": "wyu_qf2llm..."
}
Below you'll find some examples of how to implement the authentication endpoint in your backend, one for a Node.js
server, and one for ASP.NET
.
Node.js
app.get("/token", async (req, res) => {
// get user from session
let username = req.session.user;
// check local token store for existing access_token
if(_tokens.find((t) => t.username == username)){
res.json({ access_token: _tokens.find((t) => t.username == username).access_token});
}
// if not found, request token from Weavy environment
let response = await fetch(`${WEAVY-SERVER}/api/users/${username}/tokens`, {
method: 'POST',
headers: { 'Authorization': `Bearer ${WEAVY-API-KEY}` }
});
if(response.ok){
let data = await response.json();
// store and return the access token
_tokens = [..._tokens.filter((t) => t.username !== username), { username: username, access_token: data.access_token}];
res.json(data);
} else{
res.json({ message: "Could not get access token from server" })
}
});
ASP.NET
[HttpGet("~/token")]
public async Task<IActionResult> GetToken(bool refresh = false) {
// get uid for the authenticated user
var uid = User.Identity.Name;
// check local token store for existing access_token
if (!refresh && _tokens.TryGetValue(uid, out var existingToken)) {
// return existing token
return Content(existingToken);
}
// get weavy url and api key from config
var weavyUrl = _config["WEAVY-SERVER"];
var apiKey = _config["WEAVY-API-KEY"];
// request access_token from Weavy
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
var response = await _httpClient.PostAsync($"{weavyUrl}/api/users/{uid}/tokens", null);
if (response.IsSuccessStatusCode) {
// read access_token
var resp = await response.Content.ReadFromJsonAsync<TokenResponse>();
var accessToken = resp.AccessToken;
// store and return access_token
_tokens[uid] = accessToken;
return Content(accessToken);
}
return BadRequest();
}
Best practices
Below are some recommendations to keep in mind when using tokens.
Keep it secret. Keep it safe
A token should be treated like any other credential and revealed only to services that need it.
Give tokens an expiration
Technically, once a token is created, it is valid forever—unless it is revoked and/or configured to expire. This could pose potential issues so you should develop a strategy for expiring and/or revoking tokens.
Embrace HTTPS
Do not send tokens over HTTP connections as those requests can be intercepted and tokens compromised.
Store and reuse
Reduce unnecessary roundtrips that extend your application's attack surface, by storing and re-using tokens. Rather than always creating or requesting new tokens, use the stored tokens during future calls until they expire. How you decide to store your tokens is crucial to defending your application against malicious attacks. Typical solutions include databases and configuration files.