Create Custome DashBoard

Hi,

I am upgrading a custom dashboard I built for Umbraco 13 to 17, and I have hit a problem, I seem to have the controller working but when I call it I get 401.

[ApiController]
//[Authorize(Policy = AuthorizationPolicies.BackOfficeAccess)]
public class ScheduledContentController :Controller {

[Route("api/ScheduledContentDash/")]
[Authorize(Roles = "admin")]
[HttpGet]
public JsonResult getContent()
{

}

}

When I try and call it using

function loadData() {
fetch(‘/api/ScheduledContentDash/’).then(function (response) {
// The API call was successful!
console.log(‘success!’, response);
console.log(‘Jason Return!’,response.json());

}).catch(function (err) {
    // There was an error
    console.warn('Something went wrong.', err);
});

}

I have worked out I need the Bear token, but I can’t work out how to get it in Vanilla Javascript.

Can someone point me in the correct direction please.

Hey! So I’ve been going back and forth on this :grinning_face_with_smiling_eyes:i was actually workong on a coustom dashboard for our client here are two approaches that actually work in v17, pick whichever fits your setup better., maybe1,

Option 1 Plain ControllerBase with backoffice route (simpler)

this is the cleanest approach. No bearer token needed, the backoffice session cookie handles auth:

[ApiController]
[Route("umbraco/backoffice/api/v1/[controller]")]
public class ScheduledContentController : ControllerBase
{
    [HttpGet("getcontent")]
    public IActionResult GetContent()
    {
        return Ok(new { message = "works" });
    }
}

js

async function loadData() {
    const response = await fetch('/umbraco/backoffice/api/v1/scheduledcontent/getcontent', {
        method: 'GET',
        credentials: 'same-origin',
        headers: {
            'Content-Type': 'application/json',
            'Accept': 'application/json'
        }
    });

    if (!response.ok) throw new Error(`HTTP error! ${response.status}`);
    const data = await response.json();
    console.log(data);
}

The key thing here is the route prefix /umbraco/backoffice/api/v1/ — your current /api/ prefix is likely why you’re getting the 401.


Option 2 UmbControllerBase with proper auth context (TypeScript), maybe not but still good to include

If you’re open to TypeScript and the Umbraco component system, this is the more “correct” v17 way uses UMB_AUTH_CONTEXT to get the bearer token cleanly:

ts

import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import { UMB_AUTH_CONTEXT } from '@umbraco-cms/backoffice/auth';

export class ScheduledContentRepository extends UmbControllerBase {

    private async getAuthHeaders(): Promise<HeadersInit> {
        const authContext = await this.getContext(UMB_AUTH_CONTEXT);
        const token = await authContext?.getLatestToken();
        return {
            'Content-Type': 'application/json',
            ...(token ? { 'Authorization': `Bearer ${token}` } : {}),
        };
    }

    async getContent() {
        const headers = await this.getAuthHeaders();
        const response = await fetch('/umbraco/backoffice/api/v1/scheduledcontent/getcontent', {
            headers,
            credentials: 'include',
        });
        if (!response.ok) return null;
        return await response.json();
    }
}

Full working example of Option 2 in our TagManager package if it helps: Umbraco-Tag-Manager/TagManager/Client/src/api/tagmanager-repository.ts at main · ZAAKS/Umbraco-Tag-Manager · GitHub

For dashboards in the backoffice (or any endpoint that is meant only for the backoffice) you should really use a Management API controller. This will handle authentication for you.