Playing Next Lesson In
Transcript
-
Now, because the front end portion of this web application is using inertia, we're using DTOs to describe the shape
-
of our Lucid models. So over here on the left-hand side, you'll see a number of different DTOs for each one of the models used inside of this application.
-
Now we're not directly using a model for our access tokens, but we're still gonna wanna use a DTO to describe the shape of an access token whenever it comes to listing them
-
inside of that web application. So real quick, let's go ahead and right-click our DTOs and create a new file here. And we can call this access_token.ts.
-
We can export default class, access_token.dto, and have this extend the base DTO helper
-
from the attacast.com DTO package. Then let's declare that this class will have an ID, and the type of that will be number for us,
-
but the access_token package also supports strings or big ints for this as well. Then we'll declare the type column, which will be of type string.
-
Let's declare the name of the token. That too will be a string. Then we have the token itself, which will be an optional string. The abilities of the token.
-
So we'll have abilities there, and that will be a string array. When the token was last used, so last_used_at, that'll be an optional string.
-
It'll come through as a lux and date time, but we'll want to convert that to a string for the conversion over to our front end. And we also have the expiry date for that as expires_at,
-
that'll be an optional string. And then we have the timestamps of created_at, which is a string. And then we also have updated_at, which is also a string.
-
Then we get ourselves a constructor going that will accept in an access_token of type access_token,
-
which comes from the AdonisJS auth_access_tokens package. And then inside of this constructor, we'll call super since it extends, and then we can fill each one of these out. So I'm going to get multi cursors going
-
by doing option, command and up arrow here, and then option, right arrow to jump over whole words. And I'm just gonna select these property names,
-
and then we can jump back down into our constructor and paste them in, get them all at the same indentation level. And then we can do multi cursors again,
-
option, command, up arrow, prefix it with this, option, right arrow to jump over the whole word, equals access_token. And then paste the property names back in.
-
For the most part, they'll match one to one. We do have a few outliers here. The ID is not called ID, but rather identifier. Next, the token is not actually called token,
-
but rather value. And then this is optional as well. It's only going to be populated whenever we create the access token. So whenever we list out our access tokens, this is not gonna be here.
-
So this is a way for us to show the user what their access token is one time, allow them to copy it to their clipboard and then make use of it wherever they need. And then furthermore,
-
anytime that we list out the access tokens from there, this will be omitted. So in order to get the underlying value of the token, we want to call release there.
-
We need to call release because the token itself is wrapped in a secret helper, which is going to ensure that this token value
-
doesn't accidentally leak without our explicit knowledge. So by releasing that value, we're unwrapping the secret to get the actual value there.
-
Then we have some property name, red squigglies. These are all because these are lux and date times and we need to convert them to strings.
-
So we'll do question mark dot two ISO string, like so for those. And then our name red squiggly, it looks like, oh, this is actually nullable.
-
So we'll do string or null for the name there to make that happy. Okay, cool. So we have our access token DTO set up and ready to go. We'll make use of that here in the next couple of lessons.
-
While we're here setting things up though, let's also set up our tokens abilities, which we've mentioned throughout both the migration as well as this DTO here.
-
So token abilities are the ability of the token itself. We saw this whenever we walked through what we would be building, I think it was in the first lesson. So we'll be able to select whether or not
-
the token should be able to read, create, update, or delete. You can expand upon the abilities from there, but you shouldn't conflate them or confuse them
-
with actual role-based authorization checks. They are abilities that the token's meant to be able to do within our application.
-
So when we get a request with an authenticated organization, we'll be able to check the abilities to see whether or not that token is meant to be able to read, create, update, or delete.
-
So we can normalize our naming for those by defining an enum for them. So within our enums, let's right click new file, and we'll call this token_actions.ts.
-
Within here, we'll define an enum called token_actions, and we'll have a key for read, which will equal the string of read.
-
We'll do another for create, one more for updates, and then a last one for delete.
-
Then we can go ahead and export default token actions. And I missed my comma. There we go, now I got my commas added. And we can set up a quick action
-
to check against these authorizations as well. So we have this abilities action folder where we're using get abilities for our web-based authorization checks
-
to see whether or not the user's able to perform certain actions based off of their role within an organization. So add another ability specific to our access token.
-
So let's right click this new file, and we'll call this authorize_token.ts,
-
and we'll export default class authorize token, and we'll have a static action method
-
that takes in an organization as well as an action. And let's define a type up here at the top called params of type organization,
-
which will be our organization model, and then an action, which will be of type token actions, which we've just defined in enum four. Jump back down to our action method
-
and give that our params type. Inside of this action, we'll want to check and see whether or not the organization's currently used access token
-
has the ability to perform whatever the action is that we're passing in here. So read, update, create, and delete. We can do that with an if check.
-
So if not organization, now, as we've seen alluded to by the type of our API authentication guard, our organization's going to have
-
a current access token property appended onto it. And as a reminder, that's done by our tokens guard within our API auth configuration.
-
However, the model doesn't currently have that property defined as a type. So if we try to use that property, so current access token,
-
TypeScript's not going to know that it's there and available despite that provider adding the value onto the model. So we need to let TypeScript know about that as well.
-
So we can go ahead and jump into our organization model real quick and add it on. So we'll declare current access token
-
as an optional access token type, which comes from the AdonisJS auth access tokens package. This access tokens type
-
is not the direct access token itself, but rather a class that allows us to directly work with the current access token for the request.
-
So if we take a look at that class itself, it's going to have a couple of methods that are static on it, but then it's also going to have instance level methods
-
like the token identifier, the tokenable ID value, which would contain the token itself, the name of the token, type hash created at,
-
and all of that fun stuff, as well as the abilities. And then a couple of methods here that allows us to work with the token, like checking whether or not the token
-
has a particular ability, whether it denies an ability. We can authorize an ability for the access token, check whether or not it's expired, verify the validity of it,
-
and then obviously convert it to JSON. So that is everything that's on that access token class for us to make use of. So we'll give that a save and we can close that file out
-
and jump back now to our authorized tokens, where we're going to want to check and see whether or not this access token allows the action ability being passed into this method.
-
If the token then has the action ability that we're passing into the allows method within the abilities array of the token itself, then it will allow this to move onward. If it doesn't,
-
that's where we're going to want to throw an exception. And we can throw our forbidden exception with the string, the provided token does not have permission
-
to add the action name in, in this organization. So that would read something like, the provided token does not have permission
-
to read in this organization, update, create, delete, whatever the action is there. And then this is a custom exception that we added into the previous series
-
with a status code of 403. So by throwing the exception there, we are forbidding the action and stopping the request from continuing onward. And we can give ourselves a little bit of a nicer API
-
to work with here as well by adding specific methods to individual actions. So for example, we could add a read method that just takes in the organization
-
and then returns this action and then passes that organization in and then the action name of token actions.read.
-
And then we can copy that, paste it in three more times. So two and three, renaming one to create, the other to update,
-
and the last one to delete or destroy. And we also want to update the actions for their method name there as well. So update and then delete.
-
So as we build out our API controllers, we're going to be able to use this class to then authorize whether or not that token has the ability to perform an action
-
against the current access token populated and used for the request.
Defining Access Token Abilities & DTO
We'll finish up our preparation work by creating a data transfer object (DTO) for our access tokens. Then, we'll define what our token abilities will be within our application's API.

- Created by
- @tomgobich
- Published
Join the Discussion 0 comments
Be the first to comment!