diff --git a/src/Umbraco.Web.UI.Client/src/apps/app/app.element.ts b/src/Umbraco.Web.UI.Client/src/apps/app/app.element.ts index 1663dd3d26..88aa57b3ef 100644 --- a/src/Umbraco.Web.UI.Client/src/apps/app/app.element.ts +++ b/src/Umbraco.Web.UI.Client/src/apps/app/app.element.ts @@ -136,6 +136,7 @@ export class UmbAppElement extends UmbLitElement { // Instruct all requests to use the auth flow to get and use the access_token for all subsequent requests OpenAPI.TOKEN = () => this.#authContext!.getLatestToken(); OpenAPI.WITH_CREDENTIALS = true; + OpenAPI.CREDENTIALS = 'include'; } #redirect() { diff --git a/src/Umbraco.Web.UI.Client/src/shared/auth/auth.context.ts b/src/Umbraco.Web.UI.Client/src/shared/auth/auth.context.ts index 7fa2415579..21cbf444cd 100644 --- a/src/Umbraco.Web.UI.Client/src/shared/auth/auth.context.ts +++ b/src/Umbraco.Web.UI.Client/src/shared/auth/auth.context.ts @@ -1,21 +1,25 @@ import { UmbAuthFlow } from './auth-flow.js'; import { UMB_AUTH_CONTEXT } from './auth.context.token.js'; +import type { UmbOpenApiConfiguration } from './models/openApiConfiguration.js'; import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api'; import { UmbBaseController } from '@umbraco-cms/backoffice/class-api'; import { UmbBooleanState } from '@umbraco-cms/backoffice/observable-api'; +import { OpenAPI } from '@umbraco-cms/backoffice/backend-api'; export class UmbAuthContext extends UmbBaseController { #isAuthorized = new UmbBooleanState(false); readonly isAuthorized = this.#isAuthorized.asObservable(); #isBypassed = false; - #backofficePath: string; - + #serverUrl; + #backofficePath; #authFlow; + #openApi = OpenAPI; constructor(host: UmbControllerHostElement, serverUrl: string, backofficePath: string, isBypassed: boolean) { super(host); this.#isBypassed = isBypassed; + this.#serverUrl = serverUrl; this.#backofficePath = backofficePath; this.#authFlow = new UmbAuthFlow(serverUrl, this.#getRedirectUrl()); @@ -65,7 +69,7 @@ export class UmbAuthContext extends UmbBaseController { * * NB! The user may experience being redirected to the login screen if the token is expired. * - * @example + * @example Using the latest token * ```js * const token = await authContext.getLatestToken(); * const result = await fetch('https://my-api.com', { headers: { Authorization: `Bearer ${token}` } }); @@ -94,6 +98,51 @@ export class UmbAuthContext extends UmbBaseController { return this.#authFlow.signOut(); } + /** + * Get the server url to the Management API. + * @memberof UmbAuthContext + * @example Using the server url + * ```js + * const serverUrl = authContext.getServerUrl(); + * OpenAPI.BASE = serverUrl; + * ``` + * @example + * ```js + * const serverUrl = authContext.getServerUrl(); + * const token = await authContext.getLatestToken(); + * const result = await fetch(`${serverUrl}/umbraco/management/api/v1/my-resource`, { headers: { Authorization: `Bearer ${token}` } }); + * ``` + * @returns The server url to the Management API + */ + getServerUrl() { + return this.#serverUrl; + } + + /** + * Get the default OpenAPI configuration, which is set up to communicate with the Management API. + * @remark This is useful if you want to communicate with your own resources generated by the [openapi-typescript-codegen](https://github.com/ferdikoomen/openapi-typescript-codegen) library. + * @memberof UmbAuthContext + * + * @example Using the default OpenAPI configuration + * ```js + * const defaultOpenApi = authContext.getOpenApiConfiguration(); + * OpenAPI.BASE = defaultOpenApi.base; + * OpenAPI.WITH_CREDENTIALS = defaultOpenApi.withCredentials; + * OpenAPI.CREDENTIALS = defaultOpenApi.credentials; + * OpenAPI.TOKEN = defaultOpenApi.token; + * ``` + * @returns The default OpenAPI configuration + */ + getOpenApiConfiguration(): UmbOpenApiConfiguration { + return { + base: OpenAPI.BASE, + version: OpenAPI.VERSION, + withCredentials: OpenAPI.WITH_CREDENTIALS, + credentials: OpenAPI.CREDENTIALS, + token: () => this.getLatestToken(), + }; + } + #getRedirectUrl() { return `${window.location.origin}${this.#backofficePath}`; } diff --git a/src/Umbraco.Web.UI.Client/src/shared/auth/index.ts b/src/Umbraco.Web.UI.Client/src/shared/auth/index.ts index e2633039d7..e6dc7d478d 100644 --- a/src/Umbraco.Web.UI.Client/src/shared/auth/index.ts +++ b/src/Umbraco.Web.UI.Client/src/shared/auth/index.ts @@ -1,2 +1,3 @@ export * from './auth.context.js'; export * from './auth.context.token.js'; +export * from './models/openApiConfiguration.js'; diff --git a/src/Umbraco.Web.UI.Client/src/shared/auth/models/openApiConfiguration.ts b/src/Umbraco.Web.UI.Client/src/shared/auth/models/openApiConfiguration.ts new file mode 100644 index 0000000000..0bdc8ea97a --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/shared/auth/models/openApiConfiguration.ts @@ -0,0 +1,32 @@ +/** + * Configuration for the OpenAPI (Umbraco) server. This is used to communicate with the Management API. + * This is useful if you want to configure your Fetch, Axios or other HTTP client to communicate with the Management API. + * If you use the recommended resource generator [openapi-typescript-codegen](https://github.com/ferdikoomen/openapi-typescript-codegen) this can be used to configure the `OpenAPI` object. + */ +export interface UmbOpenApiConfiguration { + /** + * The base URL of the OpenAPI (Umbraco) server. + */ + readonly base: string; + + /** + * The configured version of the Management API to use. + */ + readonly version: string; + + /** + * The `withCredentials` option for the Fetch API. + */ + readonly withCredentials: boolean; + + /** + * The `credentials` option for the Fetch API. + */ + readonly credentials: 'include' | 'omit' | 'same-origin'; + + /** + * The token to use for the Authorization header. + * @returns A resolver for the token to use for the Authorization header. + */ + readonly token: () => Promise; +}