An Interest In:
Web News this Week
- March 20, 2024
- March 19, 2024
- March 18, 2024
- March 17, 2024
- March 16, 2024
- March 15, 2024
- March 14, 2024
Securing and caching your Hyperlambda endpoints
In this article we build upon the work we did in our previous article where we created our first manual Hyperlambda endpoint wrapping an SQL query. This article also has an associated YouTube video you can find below.
Security and JWT tokens in Magic
Magic is built upon JWT. JWT is an Open Standard for authentication and authorisation. You can read more about JWT at JWT.io. JWT tokens are what's referred to as "transparent authorisation tokens". This implies you can parse them semantically in your frontend, to see things such as username, roles, and other claims associated with the user. In a later article we will look at how you can create JWT tokens in Magic to authenticate users, but for now realising how to secure your Hyperlambda endpoints such that only authorised users can invoke them is sufficient.
To demand that a user belongs to one or more roles, you'd typically use the [auth.ticket.verify] slot. This slot simply throws an exception unless your user belongs to one of the comma separated roles you pass in as an argument to its invocation. Below is the code we started out with in the above video for your convenience.
.arguments genre:string// This line throws unless user belongs to root or admin roleauth.ticket.verify:root, adminsqlite.connect:chinook sqlite.select:@"select distinct c.Email, c.FirstName, c.LastName, g.name from Customer c inner join Invoice i on c.CustomerId = i.CustomerId inner join InvoiceLine ii on i.InvoiceId = ii.InvoiceId inner join Track t ON ii.TrackId = t.TrackId inner join Genre g ON t.GenreId = g.GenreId where g.Name = @genre order by c.Email" @genre:x:@.arguments/*/genre return:x:-/*
If you modify your Hyperlambda file from our previous article and exchange its content with the above, and you try to invoke the endpoint in an incognito browser window, you'll be given a 401 error saying "access denied". This is because your browser does not associate the correct JWT token with your request.
This allows you to apply RBAC for your endpoints, implying "Role Based Access Control", to control who's got access to invoke your endpoints. RBAC is a well known authorisation mechanism for controlling who's got access to your application, and of course managing users and roles in Magic is extremely easy. Below is a screenshot of adding a user to a role from your Magic dashboard.
A user can belong to one or more roles, and each endpoint can be locked for all users except those belonging to one or more roles. This pattern allows you to easily control who's got access to invoke what endpoint on your server.
Caching and the HTTP response object
In the last parts of the above video we go through how you can add HTTP headers that are returned back to the client. Specifically, we apply the Cache-Control
HTTP header, which allows the client to cache the response object for "n amount of seconds". For endpoints that rarely changes their result given the same QUERY parameters, this is an easy win in regards to optimisations, and makes sure you application becomes much faster, and that the frontend becomes much more responsive, since it allows the browser to cache the endpoint's result for some pre-defined amount of time. You can find the complete code we're using to apply cache below.
.arguments genre:stringauth.ticket.verify:root, admin// This line of code will cache your response for 200 secondsresponse.headers.set Cache-Control:private, max-age=200sqlite.connect:chinook sqlite.select:@"select distinct c.Email, c.FirstName, c.LastName, g.name from Customer c inner join Invoice i on c.CustomerId = i.CustomerId inner join InvoiceLine ii on i.InvoiceId = ii.InvoiceId inner join Track t ON ii.TrackId = t.TrackId inner join Genre g ON t.GenreId = g.GenreId where g.Name = @genre order by c.Email" @genre:x:@.arguments/*/genre return:x:-/*
Validators
A validator is kind of like a "reusable business rule component", and in Magic there exists server side validators for most things you can imagine, such as email addresses, integer numbers, date and time objects, etc - And they are typically one liners and easily applied in your Hyperlambda. Below is the example code from our YouTube video where we apply a validator for our [foo] integer argument.
.arguments genre:string foo:intauth.ticket.verify:root, admin// This makes the genre argument mandatory.validators.mandatory:x:@.arguments/*/genre// This ensure the [foo] argument is between 100 and 200validators.integer:x:@.arguments/*/foo min:100 max:200response.headers.set Cache-Control:private, max-age=200sqlite.connect:chinook sqlite.select:@"select distinct c.Email, c.FirstName, c.LastName, g.name from Customer c inner join Invoice i on c.CustomerId = i.CustomerId inner join InvoiceLine ii on i.InvoiceId = ii.InvoiceId inner join Track t ON ii.TrackId = t.TrackId inner join Genre g ON t.GenreId = g.GenreId where g.Name = @genre order by c.Email" @genre:x:@.arguments/*/genre return:x:-/*
Notice the subtle parts above where [genre] is mandatory, but [foo] is not mandatory. However, if [foo] is given, it has to have a value between 100 and 200. If you wanted the [foo] argument to also be mandatory, you'd have to add a mandatory validator for it.
In later articles we will dive deeper into Hyperlambda validators.
Original Link: https://dev.to/polterguy/securing-and-caching-your-hyperlambda-endpoints-25kc
Dev To
An online community for sharing and discovering great ideas, having debates, and making friendsMore About this Source Visit Dev To