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