Async field in Ember adapter

I have the following situation:

export default class ApplicationAdapter extends JSONAPIAdapter {
  @service auth;
  @tracked bearer;

  namespace = 'api/v1';
  host = ENV.host;
  headers = {
    'Authorization': this.authorize()
  }

  async authorize() {
    const accessToken = await this.auth.checkLogin();
    return `Bearer ${accessToken}`;
  }
}

as I want to to get the accessToken from the async checkLogin function in my not-async headers it does not work. I get a authorization: [object Promise] back and not the accesstoken.

How do I solve this as I cannot make the headers field async?

Ember simple auth handles this by abstracting the authorization stuff to the session service and using headers as a computed like this:

  // app/adapters/application.js
  import JSONAPIAdapter from '@ember-data/adapter/json-api';
  import DataAdapterMixin from 'ember-simple-auth/mixins/data-adapter-mixin';
  import { computed } from '@ember/object';
  export default class ApplicationAdapter extends JSONAPIAdapter.extend(DataAdapterMixin) {
    @computed('session.data.authenticated.token')
    get headers() {
      let headers = {};
      if (this.session.isAuthenticated) {
        headers['Authorization'] = `Bearer ${this.session.data.authenticated.token}`;
      }
      return headers;
    }
  }

This is more robust in that it will recalculate the headers anytime the session data changes. Setting the headers statically as in your example will obviously only set them once on adapter construction.

You could also try returning a proxy from your authorize method that resolves to the token so the consumer (headers) doesn’t need to be async aware.

I am trying to use the @auth0/auth0-spa-js library for this. So there is no other way to do this?

I’m not sure what you mean by “no other way”. There are a number of ways to do what you want, and your code is probably fairly close to working (though again at minimum you’ll probably need to use a Proxy instead of just returning the string from an async function).

Personally I’d follow the general pattern that ember simple auth is using (e.g. computed headers getting the token from a service where it is cached). It probably also makes sense to abstract your authentication logic into a service. A service is often a good abstraction for a third party library or API.

And of course if you wanted you could probably just use ember-simple-auth instead of hand rolling this code (i know there’s an auth0 plugin for it, not sure it it’s what you need specifically though)