https://discord.umbraco.com logo
#help-with-umbraco
[Solved] v14: Using custom authenticated controllers with the new backoffice.
# help-with-umbraco
k

kevinjump

01/30/2024, 2:56 PM
Hi, but of a big ask this one - but wondering if anyone can give me pointers on using Authentication with your own controllers and the new backoffice ? I have a (very nearly) working demo of a dashboard, using a context, and repository, and a datastore and a openapi generated resource to talk to a newly constructed API (using the management api structures, showing its own swagger) to get some simple info from the server (in my case here, time and date as strings). https://github.com/KevinJump/TimeDashboard/tree/master this works !! when the
[Authorize(Policy = "New" + AuthorizationPolicies.BackOfficeAccess)]
tag is removed from the controller (so it has no auth!). put it on, and the dashboard, does 'your session has expired' I have gone down the road of replicating some of the extra swagger stuff from the core, https://github.com/KevinJump/TimeDashboard/blob/master/TimeDashboard.Client/Configuration/ConfigureSwaggerGenOptions.cs (replacing the filters with ones that look for 'time' instead of 'management' for the API) but i suspect i am either missing something obvious, or this isn't the way to do this. anyone, any clues ? https://cdn.discordapp.com/attachments/1201903877721698395/1201903878304714783/image.png?ex=65cb8336&is=65b90e36&hm=61812c01435b7be7c7e3caf50ff9c27311838a80170d47d6158af10249b1c541&
n

nikcio

01/30/2024, 3:19 PM
Also Swagger is only documentation for your API so it shouldn't change the behavior of your endpoint only what is shown at /Swagger 😉
k

kevinjump

01/30/2024, 3:26 PM
thanks, will take a look, can't i piggy back on the existing polcieis for the backoffice ? you do need some of the sec stuff on swagger though? because it changes whats generated by the OpenAPI command line (noticed the 401 line appearing and disappearing as i've been messing with the config.
Not really getting anywhere with polcies. 😞 defineing a policy in the composer:
Copy code
cs
    private static void CreatePolicies(AuthorizationOptions options,
        string BackofficeAuthenticationScheme = Constants.Security.BackOfficeAuthenticationType)
    {
        options.AddPolicy(TimeAuthorizationPolicies.TimeDashboardAccess, policy =>
        {
            policy.AuthenticationSchemes.Add(BackofficeAuthenticationScheme);
            policy.Requirements.Add(new BackOfficeRequirement());
        });
    }
attaching it to the head of the controller
Copy code
cs 

[ApiController]
[VersionedApiBackOfficeRoute("time")]
[Authorize(Policy = TimeAuthorizationPolicies.TimeDashboardAccess)]
[MapToApi("time")]
[JsonOptionsName("time")]
public class TimeDashboardControllerBase
gets me the login screen returned via the call
d

d_inventor

01/30/2024, 4:03 PM
I'm guessing you need some sort of login / antiforgery token from the core on the frontend. I know in the old backoffice, the
$http
service was loaded with an antiforgery token by the core. I would guess there is something similar in the new backoffice?
k

kevinjump

01/30/2024, 4:08 PM
yeah - I've been looking in all the source code for v14 (front end and backend) for something like that but i can't see anything 😞
d

d_inventor

01/30/2024, 4:10 PM
k

kevinjump

01/30/2024, 4:37 PM
Yes thanks, that sent me off down the right track 🎉 The Auth context is used to set the token on the OpenAPI configuration in the main umbraco application, and any requests coming from that code then use the token. The issue is you need to generate your own code from your own OpenAPI schema, and when you do that, the code generates a new set of core files including your own OpenApi configuration 🫣 so what you need to to is use the auth to set the token on your own configuration. here (and it will be put somewhere public) . for reference: consume the auth context, and set the token on your own OpenApi configuration
Copy code
ts
this.consumeContext(UMB_AUTH_CONTEXT, (_auth) => {
    OpenAPI.TOKEN = ()=> _auth.getLatestToken();
    OpenAPI.WITH_CREDENTIALS = true;
});
then this all works with the 'standard` Polices (no need to create your own etc)
d

d_inventor

01/30/2024, 4:38 PM
awesome!!
c

Corné Hoskam

01/31/2024, 7:59 AM
bookmarks this thread for future reference This is a documentation worthy questions!
j

Jacob Overgaard

01/31/2024, 8:08 AM
@kevinjump glad you were able to figure it out... We have been contemplating if we should let out
OpenAPI
object be generally available to use for your own controllers. That would work if you use the same generator as we do in the backoffice source. Then we'd already have configured it globally for you. If you use another generator, or you use something like the named API option from ours, or maybe you want to make a standard Fetch request, you can always consume
UMB_AUTH_CONTEXT
and call the
getLatestToken()
method.
@Corné Hoskam I was just thinking the same, that's definitely something we'd like to include in the backoffice docs
k

kevinjump

01/31/2024, 8:49 AM
Documentation (like properly written with *real *words) isn't my strength. - but I've put the whole process for getting the frontend talking to the backend in this set of posts https://dev.to/kevinjump/series/26248
@Jacob Overgaard I am not sure it will actually help making the core OpenApi stuff public 🤔 at the moment if you use the OpenAPI-typescript tool, it will generate all of your client side code to reference it's own version of the OpenApi config in the
core
folder to change that you would have to go into all of the auto generated files and change the references, personally i wouldn't want to touch those files as i want to be able to regenerate them whenever the api changes - and i would likey forget. so it seems like duplication, but actually i would guess its better to let the tool generate it's code and then insert these values into config from the auth context ??
j

Jacob Overgaard

01/31/2024, 8:54 AM
I was just thinking we make our OpenAPI object available on window.umbraco.OpenAPI and in your code, you do something like:
Copy code
OpenAPI = window.umbraco.OpenAPI
and you would have the baseURL and token set up for you
but of course we can't guarantee that the OpenAPI object has the same properties if our versions of the typescript generator, which creates the object, differ
I dont know if it would be worth pursuing something like that
BTW I think you are missing the
baseURL
option in the authentication section on your blog series...? It's not a big deal, but if you wanted to host the backoffice client somewhere else, you wouldn't be able to call the server since it's no longer relative to your client. We use it extensively since our Vite dev server runs on another port
sorry it's called
BASE
not
baseURL
k

kevinjump

01/31/2024, 9:06 AM
Ahh ... thanks ! i just found that, and yes it would be better if the whole OpenApi config was public (even if there was an authContext
getOpenApiConfig
or something) because then i could get it from there and if the method for calculating the base url ever changed in the core i would be using the same value. 👍
j

Jacob Overgaard

01/31/2024, 9:07 AM
indeed
and ya, probably better to put it in the UmbAuthContext
It would look something like this, Kevin: https://github.com/umbraco/Umbraco.CMS.Backoffice/pull/1179
Also I noticed that you can in fact import our OpenAPI object through the import map available like this:
Copy code
js
import { OpenAPI } from '@umbraco-cms/backoffice/backend-api';
k

kevinjump

01/31/2024, 10:01 AM
yes 👍
j

Jacob Overgaard

01/31/2024, 10:04 AM
Actually if you have time at some point, Kevin, would you test if that works?
Copy code
js
import { OpenAPI } from './your-own-generated-code'
import { OpenAPI as umbracoOpenAPI } from '@umbraco-cms/backoffice/backend-api'

OpenAPI = umbracoOpenAPI
k

kevinjump

01/31/2024, 10:13 AM
I can't find it in umbraco-cms/backoffice/backend-api, but i did get it from
@umbraco-cms/backoffice/external/backend-api
? anyway, you can't assign it 😦 https://cdn.discordapp.com/attachments/1201903877721698395/1202195037287616542/image.png?ex=65cc9260&is=65ba1d60&hm=c55edd1522dcc0c543e5a4225334df01e964fdaf9f80293cc6d87927fc2e7096&
can set each one ...
Copy code
OpenAPI.TOKEN = umbracoOpenAPI.TOKEN;
OpenAPI.BASE = umbracoOpenAPI.BASE;
OpenAPI.WITH_CREDENTIALS = umbracoOpenAPI.WITH_CREDENTIALS;
but that import doesn't actually work 😦 - so can't yet test if that works....
not sure it is exposed in preview004 ?
j

Jacob Overgaard

01/31/2024, 10:24 AM
you are right, it's exported through external/backend-api
but .TOKEN and .BASE would not be set until the element has spun up, so there's probably some timing to it
with the PR I linked, you'd request them through the UmbAuthContext so it would already be configured when you get ahold of it
k

kevinjump

01/31/2024, 10:51 AM
yeah - i think getting them through the context seems like the right way, its a pity the gen tool can't be told to import the config from somewhere diffrent - that would be a good solution, i might see what would be involed in a PR for that.
j

Jacob Overgaard

01/31/2024, 12:53 PM
yeah in a non-module context the OpenAPI object is just a global object available on the window, so any generated resources be it ours or yours use it automatically, but es modules are scoped and won't leak it automatically so you have to overwrite it somehow
s

Sebastiaan

02/01/2024, 12:27 PM
16 Views