This video has been updated: ruclips.net/video/BWUi6BS9T5Y/видео.html The updated version is much better so please watch that one instead of this video.
Hey Tom whats the difference between this video and the updated one? Is there anything wrongn with this one? The other one seems more complex and longer too
This is what I call typescript speed run. Great tutorial. I feel though, that it's better to type these things out for the more intermediate or junior Software Dev Folk. since it is an Auth lesson on Typescript majorly, most people coming here are probably intermediate or junior
Hello @tomdoestech, thank you very much for the content. However, there is a suggestion I want to make: Say you want to build the login functionality please do not start from the routes, it creates some kind of confusion. Instead you could do this: 1. Start from the various utilities 2. Build your validation schema 3. Build your service 4. Then build the routes This way, it will be easy to grasp.
Thanks for this video. I'm really new to Typescript coming from a C# background. I've been finding it hard to switch from OOP to functional programming, and I'm finding your video really helpful. One thing I noticed is that you dont really specify the return types for any of your functions. Is that standard practise with TS? Personally I believe that you should be able to look at a function and know exactly what's expected to go into it, and exactly what's expected to come out of it (obviously TS makes this a little less definitive with union types, but you still have an idea which type to expect).
I generally don't specify the output, which is probably bad practice. If your functions are pure and you specify the input, TS generally does a good job of implicitly specifying the output. I think it depends on the function and what you find useful.
Solid again. Can you explain the reason why you set the newAccessToken generated from the expired refresh token to the "x-access-token" header but the initial access token uses the "authorization" header?
@@Scetils I'm glad you figured it out :) When I was first learning about REST APIs the concept of incoming and outgoing requests really confused me. Unfortunately, RUclips didn't have much good content on the topic then.
Hi Tom, could you explain why you assign posts their own postId fields and not use the automatically generated id from Mongoose instead? I would also like to know what you would advise to do to prevent a malicious user from saturating the database with fake users? thank you in advance
Hi Tom, great tutorial, I have a question why we use DocumentDefinition?, Also when should we use curly braces({ }) like here, import Post, { PostDocument } from "../model/post.model";
DocumentDefinition with your interface best matches when the model.create method takes as arguments. As for the imports, the bit outside the {} is a default export, while the but property inside is a named export. It's like importing using object destructing.
I'm trying to follow along, and I got a very weird error at 7:31 (console.log -> log.info), as log was undefined. I just couldn't figure it out. Seems like it was due to running `npm run build` at some point, and the only change needed was to remove an auto-generated src/app.js
Im on the delete section of the video, in the delete section part do you put the accessToken on the headers.authorization? im still confused in this part...
yep it turns out my accessToken is always undefined on deserializeUser.ts, where do you put the accessToken after giving it back to the user in createSessionHandler?
Thanks a lot for this video, i am just trying to understand something. you said if(!accessToken) return next(); , why though? thought it should be access denied at that point if there is no accessToken in the request and return a 403
You need to consider the path that the data takes. That middleware is run first, so if there is no access token when it gets to the requireUser middleware, the user will be null and a 403 will be sent. You don't want to return a 403 in the deserializeUser middleware because then the user has to be logged in for every request, so how will they login or register in the first place.
@@TomDoesTech Do you need to have deserializeUser middleware for every route? Could you not combine requiresUser and deserializeUser into one middleware function and only place it on protected routes?
Did I misunderstood, or are u sending with every request the accessToken and the refreshToken? And not like only sending the refreshToken when de accessToken is invalid.
@@TomDoesTech Can you explain why not just using 1 token? I have the feeling it doesn't make sense to use two different tokens in this manner. I understand it is not the main focus of this video, just wondering. (great video btw ;) )
@@bobvandoorn8761 The two tokens have two different purposes, one grants the user access to the resource, the other, given certain conditions, grants the user access to another access token.
HI @TomDoesTech I have use delete session api and that make my session valid: false. But with the same token I am able to call create post api. I think need to make some changes in deserialize middleware
When you delete the session or change valid to false, you're making sure the refresh token can't be used to generate another access token, but the current access token will still work. This is why the access tokens should have a short TTL. If you want to use the delete session like a logout, also remove the access token from the user.
I've faced to an issue with typescript and type checking. In "session.controller" I'm getting the following error: "Property '_d' does not exist on type 'false'" I've added the following type checking to the if clause but it did not help. if(typeof user === 'boolean) res.status(401).send('Invalid username or password')
I have added the following but I don't know that it is the best practice or not. const session = await createSession((user as UserDocument)._id, req.get('user-agent') || '') const accessToken = createAccessToken({ user: user as UserDocument, session})
Hi there ! First, ty for the content. It helps me to understand some stuff. However i got an issue adapting your exemple to my code. Something i never encounter comes to me ˆˆ -> I write service and model just as you can, but, when i call .create() method with input as parameters, datas disappear.. I got them in service function but they don't pass to .pre('save') method. I know it's small, but any idea what's going on ?
@@TomDoesTech Ty for you'r concerne, i figure it out but i don't understand why it happened.. I used arrow function for async function in .pre('save'). I just rewrite it with classic function and it finally works. Do you know the difference between this two ?
@@corentintruffaut7291 Yes, it has to do with scope and closures. Using the function keyword sets scope to the parent function, allowing you to get access to the `this` keyword.
Private keys are secrets for signing tokens. You then check with the public key to verify if the token was signed with the correct private key. Look up PGP encryption
APIs are just interfaces that expose the internal workings of a system. They don't always communicate over a network like REST, SOAP & GraphQL APIs. Node.js for example has a standard library and you interact with it through its API. Another example is React, when you call useState for example that's part of React's API.
That's a very broad question that has hundreds, if not thousands of answers. If it's a specific method you're after, the best thing I can point you to is this video: ruclips.net/video/2oNsjyaCIrI/видео.html
please man, stop copying everything all the time you've got some good tutorials, so please start typing them out or at least giving us 5 seconds to pause i need to pause and always skip backwards to see what you pasted
I've posted a lot of tutorials since this one and I haven't copied since this one, so I'm not sure how I stop doing something that I stopped doing over a year ago
@@TomDoesTech I tried with a refresh token but still the same error.. post: localhost.../api/posts headers: key: x-refresh value: refreshToken send 403 forbidden
@@ravincristiano add the access token in auth -> bearer token
2 года назад
literally first line of tutorial yarn : The term 'yarn' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again. LMAO
Thanks for the feedback. I'm a software developer trying to learn how to make videos. So I know my editing skills are bad but I am trying to improve them. I'll keep working on it. Got any tips on how I can improve?
@@TomDoesTech I think he means that sometimes between cuts your voice is cut off a bit, like at 14:45 for example. But apart from that, I think the video is great! It must be annoying to have such a comment without any further explanation, when you are just trying to help other people and doing your best. So in my opinion great video and keep up the good work :)
@@TomDoesTech Hey great video! But I believe it would be better if you typed it out instead of cutting the big code parts out, when you do that with a paste of big code it encourages me to copy/paste. And I rather actually learn stuff then do that.
@@poweredcity3704 Thanks for the feedback but I'm curious as to why you think that. It would be very boring watching me type and not talking while I typed everything out. I think it's much better if I paste the code and explain it, then you can copy it with an understanding of what it does.
2 года назад
I can't even connect to mongoose as i get an error on useNewUrlParser: true, TSError: ⨯ Unable to compile TypeScript: src/db/connect.ts:10:7 - error TS2769: No overload matches this call. Overload 1 of 3, '(uri: string, callback: CallbackWithoutResult): void', gave the following error. Argument of type '{ useNewUrlParser: boolean; useUnifiedTopology: boolean; }' is not assignable to parameter of type 'CallbackWithoutResult'. Object literal may only specify known properties, and 'useNewUrlParser' does not exist in type 'CallbackWithoutResult'. Overload 2 of 3, '(uri: string, options?: ConnectOptions | undefined): Promise', gave the following error. Argument of type '{ useNewUrlParser: boolean; useUnifiedTopology: boolean; }' is not assignable to parameter of type 'ConnectOptions'. Object literal may only specify known properties, and 'useNewUrlParser' does not exist in type 'ConnectOptions'. 10 useNewUrlParser: true, ~~~~~~~~~~~~~~~~~~~~~ at createTSError (F:\Programas\Coding\Mobile_Projects\BackEnd\BackEndAutoSense ode_modules\ts-node\src\index.ts:820:12) at reportTSError (F:\Programas\Coding\Mobile_Projects\BackEnd\BackEndAutoSense ode_modules\ts-node\src\index.ts:824:19) at getOutput (F:\Programas\Coding\Mobile_Projects\BackEnd\BackEndAutoSense ode_modules\ts-node\src\index.ts:1014:36) at Object.compile (F:\Programas\Coding\Mobile_Projects\BackEnd\BackEndAutoSense ode_modules\ts-node\src\index.ts:1322:43) at Module.m._compile (F:\Programas\Coding\Mobile_Projects\BackEnd\BackEndAutoSense ode_modules\ts-node\src\index.ts:1454:30) at Module._extensions..js (node:internal/modules/cjs/loader:1159:10) at Object.require.extensions. [as .ts] (F:\Programas\Coding\Mobile_Projects\BackEnd\BackEndAutoSense ode_modules\ts-node\src\index.ts:1458:12) at Module.load (node:internal/modules/cjs/loader:981:32) at Function.Module._load (node:internal/modules/cjs/loader:827:12) at Module.require (node:internal/modules/cjs/loader:1005:19) { diagnosticCodes: [ 2769 ] }
This video has been updated: ruclips.net/video/BWUi6BS9T5Y/видео.html
The updated version is much better so please watch that one instead of this video.
Hey Tom whats the difference between this video and the updated one? Is there anything wrongn with this one? The other one seems more complex and longer too
Hey Tom, doing great work.☺️ Please continue do such video which will help others to learn.
its been less than 5 minutes and already subscribed you, great video bro
Thank you so much! I am redoing this video and it's going to be 10 times better than this one, should be out next week :)
This is what I call typescript speed run. Great tutorial. I feel though, that it's better to type these things out for the more intermediate or junior Software Dev Folk. since it is an Auth lesson on Typescript majorly, most people coming here are probably intermediate or junior
It is a speed run and juniors will have to sweat a bit to connect the dots.
Wow I've never seen such sophisticated use of Postman, maybe you can make a video of your workflow with Postman
The best tutorial of Node whit Ts, thx bro!! from Mexico
Glad it helped!
Great content, Brother!! Really like your typescript stuff
Thank you so much :)
Hello @tomdoestech, thank you very much for the content.
However, there is a suggestion I want to make:
Say you want to build the login functionality please do not start from the routes, it creates some kind of confusion. Instead you could do this:
1. Start from the various utilities
2. Build your validation schema
3. Build your service
4. Then build the routes
This way, it will be easy to grasp.
This is a very thankful and helpful video....Thanks
Greetings from Brazil! Great job!
Great tutorial! The tutor has a great understanding of RESTful APIs 👌
Hey tom love your work ❤❤
Thank you so much :)
Awesome.
You're doing great!
Make another like this
Thanks for this video. I'm really new to Typescript coming from a C# background. I've been finding it hard to switch from OOP to functional programming, and I'm finding your video really helpful.
One thing I noticed is that you dont really specify the return types for any of your functions. Is that standard practise with TS? Personally I believe that you should be able to look at a function and know exactly what's expected to go into it, and exactly what's expected to come out of it (obviously TS makes this a little less definitive with union types, but you still have an idea which type to expect).
I generally don't specify the output, which is probably bad practice. If your functions are pure and you specify the input, TS generally does a good job of implicitly specifying the output.
I think it depends on the function and what you find useful.
B Kironas Thanks for the input! I'm coming to this video with the same background and your comment made me sure I would learn from this video.
Fingers crossed on this. Hope it helps me.
Let me know if you have any questions
Thanks for the informative video! I think I'll be using this controller-service type system now
Thanks a lot.I learned a lot ot things from this video.
Glad to hear that!
Looks great, Im starting the project right now
Good luck Jackie! Please let me know how you get on with it.
@@TomDoesTech thanks for your quickly answer, Ill be back for comment how its going!
Thanks another time!!
great
more videos on ts + node plz
Solid again.
Can you explain the reason why you set the newAccessToken generated from the expired refresh token to the "x-access-token" header but the initial access token uses the "authorization" header?
Hmmm that sounds like a mistake, the access token should always go in the authorization header.
@@TomDoesTech Yeah I know what was confusing me. My bad. You're attaching the token to the out going/response headers.
@@Scetils I'm glad you figured it out :)
When I was first learning about REST APIs the concept of incoming and outgoing requests really confused me. Unfortunately, RUclips didn't have much good content on the topic then.
நன்றிகள் பல...
Hi Tom, could you explain why you assign posts their own postId fields and not use the automatically generated id from Mongoose instead?
I would also like to know what you would advise to do to prevent a malicious user from saturating the database with fake users?
thank you in advance
Great work dude!!
i see u use yup in request validation, i have a question how to validate if requested email is already used (unique email)?
If you have a unique flag on the email field in the mongoose model, MongoDB will enforce unique emails.
any idea how to solve this: Namespace '"mongoose"' has no exported member 'HookNextFunction'.
Yeah, don't import or use HookNextFunction
Hi Tom, great tutorial, I have a question why we use DocumentDefinition?, Also when should we use curly braces({ }) like here, import Post, { PostDocument } from "../model/post.model";
DocumentDefinition with your interface best matches when the model.create method takes as arguments.
As for the imports, the bit outside the {} is a default export, while the but property inside is a named export. It's like importing using object destructing.
I think you forgot the part to add a clip of creating the model for the Post collections hehe
17:22 Is there an advantage in calling method "hashSync" over method "hash" ?
if Error 36:12
const accessToken = createAccessToken({ user, session});
Change
const accessToken = sign(
{...user, session: session._id},
{ expiresIn: config.get("accessTokenTtl")}
);
It’s very useful for me.. As I connect the database, it gives db error. Kindly help me solve this issue
This video made me subscribe your channel ❤️❤️
I'm trying to follow along, and I got a very weird error at 7:31 (console.log -> log.info), as log was undefined. I just couldn't figure it out. Seems like it was due to running `npm run build` at some point, and the only change needed was to remove an auto-generated src/app.js
Good job😎
If someone getting printPretty error just put this in logger
transport:{
target:"pino-pretty",
options:{
colorize:true
}
},
Awesome Tut.
Thank you so much :)
@@TomDoesTech Better than udemy :)
what font do you use in your vscode ?
Im on the delete section of the video, in the delete section part do you put the accessToken on the headers.authorization? im still confused in this part...
yep it turns out my accessToken is always undefined on deserializeUser.ts, where do you put the accessToken after giving it back to the user in createSessionHandler?
You put it in the authorization header. There is a special section for it in postman, or you can create a header called `Authorization`.
Sir I am not able to import {DocumentDefination} from mongoose
Thanks a lot for this video, i am just trying to understand something.
you said if(!accessToken) return next(); , why though? thought it should be access denied at that point if there is no accessToken in the request and return a 403
You need to consider the path that the data takes. That middleware is run first, so if there is no access token when it gets to the requireUser middleware, the user will be null and a 403 will be sent.
You don't want to return a 403 in the deserializeUser middleware because then the user has to be logged in for every request, so how will they login or register in the first place.
If that doesn't make sense I can make you up a flow diagram to help visualize the flow.
@@TomDoesTech yes please, it'll surely help. Thanks
@@NathanielBabalola There is actually a diagram on the GitHub repo
@@TomDoesTech Do you need to have deserializeUser middleware for every route? Could you not combine requiresUser and deserializeUser into one middleware function and only place it on protected routes?
Did I misunderstood, or are u sending with every request the accessToken and the refreshToken? And not like only sending the refreshToken when de accessToken is invalid.
Yeah, send it with every request to make it as seamless for the user
@@TomDoesTech Can you explain why not just using 1 token? I have the feeling it doesn't make sense to use two different tokens in this manner. I understand it is not the main focus of this video, just wondering. (great video btw ;) )
@@bobvandoorn8761 The two tokens have two different purposes, one grants the user access to the resource, the other, given certain conditions, grants the user access to another access token.
HI @TomDoesTech I have use delete session api and that make my session valid: false. But with the same token I am able to call create post api. I think need to make some changes in deserialize middleware
When you delete the session or change valid to false, you're making sure the refresh token can't be used to generate another access token, but the current access token will still work. This is why the access tokens should have a short TTL.
If you want to use the delete session like a logout, also remove the access token from the user.
I've faced to an issue with typescript and type checking.
In "session.controller" I'm getting the following error: "Property '_d' does not exist on type 'false'"
I've added the following type checking to the if clause but it did not help.
if(typeof user === 'boolean) res.status(401).send('Invalid username or password')
I have added the following but I don't know that it is the best practice or not.
const session = await createSession((user as UserDocument)._id, req.get('user-agent') || '')
const accessToken = createAccessToken({ user: user as UserDocument, session})
That's a very weird problem. If you send me a link to the repo I can take a look.
Hi there ! First, ty for the content. It helps me to understand some stuff.
However i got an issue adapting your exemple to my code. Something i never encounter comes to me ˆˆ
-> I write service and model just as you can, but, when i call .create() method with input as parameters, datas disappear.. I got them in service function but they don't pass to .pre('save') method.
I know it's small, but any idea what's going on ?
Interesting, if you can share a repository I am happy to take a look
@@TomDoesTech Ty for you'r concerne, i figure it out but i don't understand why it happened..
I used arrow function for async function in .pre('save'). I just rewrite it with classic function and it finally works.
Do you know the difference between this two ?
@@corentintruffaut7291 Yes, it has to do with scope and closures. Using the function keyword sets scope to the parent function, allowing you to get access to the `this` keyword.
@@TomDoesTech Ok, ty for the explanations !
27:15
bro why we need private kay? i did understand, can u explain this
Private keys are secrets for signing tokens. You then check with the public key to verify if the token was signed with the correct private key. Look up PGP encryption
@@TomDoesTech where to sign tokens. When we use it in rest ful api. Can it work without sing or private key?
Does all api are rest or soap api
Is there nothing like only api (pure api without any type)
APIs are just interfaces that expose the internal workings of a system. They don't always communicate over a network like REST, SOAP & GraphQL APIs. Node.js for example has a standard library and you interact with it through its API. Another example is React, when you call useState for example that's part of React's API.
@@TomDoesTech thanks for your prompt reply
Help @TomDoesTech i keep getting this error: "mongoose"' has no exported member 'HookNextFunction'
Have you installed @types/mongoose?
@@TomDoesTech yes it is installed already
try this
...
async function (
this: UserDocument,
next: (err?: Error | undefined) => void
) ....
import config from "config"
this direct import did not work for me,,, how should i make it work
I have no idea, you haven't told me anything that would help me provide a solution
@@TomDoesTech can you please provide me your linkedin profile link.. so that i can connect there.
@@dhanushreddy4836 no?
3:41
start setting
Not works with "mongoose": "^6.0.2", version. getting error.
That's a shame
works for me somehow, done some workaround also, uninstall @types/mongoose. the latest versions come with built-in types
great
is there anyone know why my get(req, "user") is returned undefined ? so i cant deleting session or anything passing requiresUser middleware ?
Have you tried logging the user object just before you do req.user = user?
@@TomDoesTech yes sir, I have log in then copy paste x-refresh from refresh token, what should I do next ?
@@wahyuramadhan9316 No, I mean using console.log to log the user object to make sure it's being deserialized properly.
in what file sir that i must logging the user object ?
@@wahyuramadhan9316 in the deserialize middleware
where can I get Private kEY?
Google "generate public and private keys online".
@@TomDoesTech is it okay if i work with the same key you used here?
@@ravincristiano Yup, I think I committed it to GH
how to deploy it?
That's a very broad question that has hundreds, if not thousands of answers. If it's a specific method you're after, the best thing I can point you to is this video: ruclips.net/video/2oNsjyaCIrI/видео.html
please man, stop copying everything all the time
you've got some good tutorials, so please start typing them out or at least giving us 5 seconds to pause
i need to pause and always skip backwards to see what you pasted
I've posted a lot of tutorials since this one and I haven't copied since this one, so I'm not sure how I stop doing something that I stopped doing over a year ago
@@TomDoesTech how would I know? just trying to give you a tip
good work
getting 403 error while creating a post.
Perfect! The Auth system works
@@TomDoesTech how to solve this error??
@@ravincristiano Send the request with a valid JWT
@@TomDoesTech I tried with a refresh token but still the same error..
post: localhost.../api/posts
headers:
key: x-refresh
value: refreshToken
send
403 forbidden
@@ravincristiano add the access token in auth -> bearer token
literally first line of tutorial
yarn : The term 'yarn' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
LMAO
You have to install yarn to be able to use it, otherwise you can use npm
This tutorial is not for beginners, it says at the start its for junior to mid-level devs
Dude you're going way too fast.
Idk you edited this video yourself or from a editor but it was just a big mess
Sorry to disappoint you. The pinned comment and description have a link to an updated version
editing is beyond terrible
Thanks for the feedback. I'm a software developer trying to learn how to make videos. So I know my editing skills are bad but I am trying to improve them. I'll keep working on it. Got any tips on how I can improve?
@@TomDoesTech I think he means that sometimes between cuts your voice is cut off a bit, like at 14:45 for example. But apart from that, I think the video is great! It must be annoying to have such a comment without any further explanation, when you are just trying to help other people and doing your best. So in my opinion great video and keep up the good work :)
@@noboss3736 Yeah i think I need to edit the noise gate I have setup
@@TomDoesTech Hey great video! But I believe it would be better if you typed it out instead of cutting the big code parts out, when you do that with a paste of big code it encourages me to copy/paste. And I rather actually learn stuff then do that.
@@poweredcity3704 Thanks for the feedback but I'm curious as to why you think that. It would be very boring watching me type and not talking while I typed everything out. I think it's much better if I paste the code and explain it, then you can copy it with an understanding of what it does.
I can't even connect to mongoose as i get an error on useNewUrlParser: true,
TSError: ⨯ Unable to compile TypeScript:
src/db/connect.ts:10:7 - error TS2769: No overload matches this call.
Overload 1 of 3, '(uri: string, callback: CallbackWithoutResult): void', gave the following error.
Argument of type '{ useNewUrlParser: boolean; useUnifiedTopology: boolean; }' is not assignable to parameter of type 'CallbackWithoutResult'.
Object literal may only specify known properties, and 'useNewUrlParser' does not exist in type 'CallbackWithoutResult'.
Overload 2 of 3, '(uri: string, options?: ConnectOptions | undefined): Promise', gave the following error.
Argument of type '{ useNewUrlParser: boolean; useUnifiedTopology: boolean; }' is not assignable to parameter of type 'ConnectOptions'.
Object literal may only specify known properties, and 'useNewUrlParser' does not exist in type 'ConnectOptions'.
10 useNewUrlParser: true,
~~~~~~~~~~~~~~~~~~~~~
at createTSError (F:\Programas\Coding\Mobile_Projects\BackEnd\BackEndAutoSense
ode_modules\ts-node\src\index.ts:820:12)
at reportTSError (F:\Programas\Coding\Mobile_Projects\BackEnd\BackEndAutoSense
ode_modules\ts-node\src\index.ts:824:19)
at getOutput (F:\Programas\Coding\Mobile_Projects\BackEnd\BackEndAutoSense
ode_modules\ts-node\src\index.ts:1014:36)
at Object.compile (F:\Programas\Coding\Mobile_Projects\BackEnd\BackEndAutoSense
ode_modules\ts-node\src\index.ts:1322:43)
at Module.m._compile (F:\Programas\Coding\Mobile_Projects\BackEnd\BackEndAutoSense
ode_modules\ts-node\src\index.ts:1454:30)
at Module._extensions..js (node:internal/modules/cjs/loader:1159:10)
at Object.require.extensions. [as .ts] (F:\Programas\Coding\Mobile_Projects\BackEnd\BackEndAutoSense
ode_modules\ts-node\src\index.ts:1458:12)
at Module.load (node:internal/modules/cjs/loader:981:32)
at Function.Module._load (node:internal/modules/cjs/loader:827:12)
at Module.require (node:internal/modules/cjs/loader:1005:19) {
diagnosticCodes: [ 2769 ]
}
Remove useNewUrlParser: true, you don't need it with the new version of mongoose
@@TomDoesTech thanks. i saw now you hyave an updated video, will watch that instead