Authentication

Your application and the Weavy environment communicate using a Web API and all requests need to be properly authenticated with Bearer authentication over HTTPS (SSL).

This article explains how to configure seamless authentication between your application and Weavy, and discusses the difference between user-to-server communication with access tokens, and server-to-server communication with API keys. Finally, we present some best practices for how to use and manage tokens.

UIKit authentication

When adding Weavy components to your application, you want the UIKit to act seamlessly on behalf of the logged in (authenticated) user. For this to work you need to configure the UIKit with a token factory. The workflow for authentication is outlined below:

Your applicationYour frontendYour backendWeavycomponent+tokenfactoryGet access tokenTokenendpointIssue access tokenWeavy environmentFetch data on behalf of logged in user
  1. When a Weavy component is initialized, it requests an access_token from the tokenFactory.
  2. The tokenFactory calls a token endpoint on your backend that identifies the logged in user and makes an API request to the Weavy environment which issues an access_token.
  3. With the access_token the component can fetch data on behalf of the logged in user and render it in your application.

Token factory

The tokenFactory is simply an async function and can be implemented anyway that fits your needs, the only requirement is that it returns a valid access token.

weavy.tokenFactory = async (refresh) => "wyu_**********";

Having said that, the way it's typically implemented is with a fetch request to a token endpoint on your backend as seen in the following example:

weavy.tokenFactory = async (refresh) => {

  // fetch access_token from token endpoint on your backend
  const response = await fetch("/token?refresh=" + refresh);

  if (response.ok) {
    const data = await response.json();

    // return access_token to UIKit
    return data.access_token;
  } else {
    throw new Error("Could not fetch token from endpoint");
  }
};

Token endpoint

The responsibility of the token endpoint is to return an access_token for the logged in user. That usually involves the following steps:

  1. Identify the logged in user (in most web applications users are identified with an authentication cookie).
  2. Fetch an access_token for the user (from local application storage or from the Weavy environment).
  3. Return the access_token to the tokenFactory.

Below you'll find some examples of how you could implement the authentication endpoint in your backend, one for a Node.js server, and one for ASP.NET.

app.get("/token", async (req, res) => {
    // get user from session
    let username = req.session.user; 

    // refresh or use existing token?
    const refresh = req.query.refresh === "true";

    // check local token store for existing access token
    if(!refresh && _tokens.find((t) => t.username == username)){        
        res.json({ access_token: _tokens.find((t) => t.username == username).access_token});        
        return;
    } 
    
    // request access token from Weavy environment
    let response = await fetch(`${WEAVY_URL}/api/users/${username}/tokens`, {
        method: 'POST',
        headers: { 'Authorization': `Bearer ${API_KEY}` }
    });
        
    if(response.ok){
        // store and return access token
        let data = await response.json();        
        _tokens = [..._tokens.filter((t) => t.username !== username), { 
          username: username, 
          access_token: data.access_token
        }];    
        res.json({ access_token: data.access_token });            
    } else{
        res.json({ message: "Could not get access token from server" })
    }
});
[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 token)) {
        // return existing token
        return Json(new { access_token = token });
    }

    // request access token from Weavy environment
    _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", API_KEY);
    var response = await _httpClient.PostAsync($"{WEAVY_URL}/api/users/{uid}/tokens", null);
    if (response.IsSuccessStatusCode) {
        // store and return access_token
        var data = await response.Content.ReadFromJsonAsync<TokenResponse>();
        _tokens[uid] = data.AccessToken;
        return Json(new { access_token = data.AccessToken });
    }

    return BadRequest();
}

Example: Response from token endpoint.

{
  "access_token": "wyu_**********"
}

To improve response times and reduce unnecessary roundtrips, it is a good practice for your application to store and reuse tokens instead of always requesting new tokens from the Weavy environment. When the UIKit detects an expired or revoked token, your tokenFactory will be called with refresh=true. If you pass this on to your token endpoint you can use it to clear the invalid token from your application’s storage and request a new token from the Weavy environment.

Token URL

The UIKit comes with a predefined token factory that can be activated by setting the tokenUrl propery. The tokenUrl should point to an endpoint that provides a JSON response with an access_token. Whenever the UIKit detects an expired or revoked token, it automatically appends the ?refresh=true query string to the url.

weavy.tokenUrl = new URL("https://example.com/myapp/token");

Note that you should provide either a tokenFactory or a tokenUrl. There's no need to specify both.

Access tokens

When you make API requests on behalf of a user, the request must contain an access_token in the Authorization header to associate the request with the user. This is known as user-to-server communication.

To obtain an access_token for a user you issue a server-to-server request to the tokens endpoint in the Users API.

API keys

Tokens used in server-to-server communication are called API keys and can be generated from the management page of your environment.

Note that 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.

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.

Ask AI
Support

To access live chat with our developer success team you need a Weavy account.

Sign in or create a Weavy account