dev-resources.site
for different kinds of informations.
Umbraco and Bellissima: Swagger, Tokens, Entry Points
These examples are meant to set up authentication in your own code in Umbraco 14+ by hooking on to the authorization mechanism of Umbraco to extract the access_token.
The following examples are tested in Umbraco 14 and 15 and I have written them here mostly to be able to quickly look up how to get started with an entry point to the Umbraco Backoffice.
Basic authentication
What we are trying to achieve is essentially to get the token to use in the Authorization
header in a fetch()
call:
fetch('/myapi/controller/endpoint', {
method: 'GET',
headers: {
'Authorization': 'Bearer 123' // <-- Token goes here
}
});
This can be wrapped in Umbraco using the Context API:
/**
* Make an authorized request to any Backoffice API.
* @param host A reference to the host element that can request a context.
* @param url The URL to request.
* @param method The HTTP method to use.
* @param body The body to send with the request (if any).
* @returns The response from the request as JSON.
*/
async function makeRequest(host: UmbClassInterface, url: string, method = 'GET', body?: any) {
const authContext = await host.getContext(UMB_AUTH_CONTEXT);
const token = await authContext.getLatestToken();
const response = await fetch(url, {
method,
body: body ? JSON.stringify(body) : undefined,
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`,
},
});
return response.json();
}
Don't do this, though. Use a TypeScript client generator instead:
TypeScript Client
I always use the latest version of @hey-api/openapi-ts to generate the TypeScript client. This library supports several clients including their own @hey-api/client-fetch that wraps the native fetch
client. The generator can also use the native Fetch API directly using the native/fetch library. Here is how to hook on to Umbraco's authentication for both clients:
First, install @hey-api/openapi-ts:
npm i --save @hey-api/openapi-ts @hey-api/client-fetch
Then create a script in package.json
:
{
"scripts": {
"generate": "openapi-ts -i http://localhost:7029/umbraco/swagger/bellissima-v1/swagger.json?urls.primaryName=Bellissima%20Management%20Api -o src/api -c @hey-api/client-fetch"
}
}
Next, create /App_Plugins/MyExtensions/umbraco-package.json
and register an extension of the type backofficeEntryPoint
:
{
"name": "My Extensions",
"alias": "My.Extensions",
"version": "1.0.0",
"extensions": [
{
"type": "backofficeEntryPoint",
"alias": "My.Entrypoint",
"name": "My Entrypoint",
"js": "/App_Plugins/MyExtensions/entry-point.js"
}
]
}
Make sure to set up a TypeScript transpiler (tsc, vite, etc) and create an entry-point.ts
file.
@hey-api/client-fetch
Add the following to entry-point.ts
:
import type { UmbEntryPointOnInit } from '@umbraco-cms/backoffice/extension-api';
import { UMB_AUTH_CONTEXT } from '@umbraco-cms/backoffice/auth';
import { client } from './api/index.js';
export const onInit: UmbEntryPointOnInit = (host) => {
host.consumeContext(UMB_AUTH_CONTEXT, (authContext) => {
// Get API config
const config = authContext.getOpenApiConfiguration();
// Set base config
client.setConfig({
baseUrl: config.base,
credentials: config.credentials
});
// Set interceptor to add authorization
client.interceptors.request.use(async (req) => {
const token = await config.token();
if (token) {
req.headers.set('Authorization', `Bearer ${token}`);
}
return req;
});
});
};
legacy/fetch
Note: This client is deprecated. To use it, replace @hey-api/client-fetch
with legacy/fetch
in the generate script.
Add the following to entry-point.ts
:
import type { UmbEntryPointOnInit } from '@umbraco-cms/backoffice/extension-api';
import { UMB_AUTH_CONTEXT } from '@umbraco-cms/backoffice/auth';
import { OpenAPI } from './api/index.js';
export const onInit: UmbEntryPointOnInit = (host) => {
host.consumeContext(UMB_AUTH_CONTEXT, (authContext) => {
// Get API config
const config = authContext.getOpenApiConfiguration();
// Set base config
OpenAPI.BASE = config.base;
OpenAPI.TOKEN = config.token;
OpenAPI.CREDENTIALS = config.credentials;
OpenAPI.WITH_CREDENTIALS = config.withCredentials;
OpenAPI.ENCODE_PATH = config.encodePath;
});
};
The entry point ensures authorization is set up before any requests are made in the Backoffice, and you can now import the generated SDK and call it from any element with or without the tryExecute
and tryExecuteAndNotify
functions.
What's Next
Now you have an entry point to the Backoffice set up with authentication from Umbraco into your API. From here, you can register any kind of extension you want using the extensionRegistry
argument on the onInit
method. Expand onInit
with the following:
export const onInit: UmbEntryPointOnInit = (host, extensionRegistry) => {
extensionRegistry.register({
type: 'X'
});
};
Replace X with whatever type you want to register. The full list is available on the UmbracoDocs.
Happy hacking.
Featured ones: