-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
116 additions
and
84 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,130 +1,162 @@ | ||
## Project in self | ||
# TypeScript API with authentication | ||
|
||
API made with Typescript, MongoDB and JsonWebToken as main technologies. | ||
This API has an **no-sesion** authentication, made by passport-jwt, for endpoints. Based on **MVC** architecture. | ||
This project purpose is to learn about JWT auth flow, using TypeScript. | ||
|
||
## To start | ||
## Run Locally | ||
|
||
### `npm install` | ||
1. Install both: | ||
|
||
To install all dependencies before run any other script. | ||
- [Node.js](https://nodejs.org/es/download/) | ||
- [MongoDB](https://www.mongodb.com/try/download/community) | ||
|
||
### `npm run dev` | ||
You will need to have MongoDB running on port 27017. | ||
|
||
Script automatically compiles tsc and watch for changes. Only runs 1 time. | ||
2. Clone the project: | ||
|
||
### `npm run build` | ||
```bash | ||
git clone https://github.com/AloisCRR/jwt-api-users-auth.git | ||
``` | ||
|
||
Compiles tsc code (this is more for production) | ||
3. Go to the project directory: | ||
|
||
### `npm start` | ||
```bash | ||
cd jwt-api-users-auth | ||
``` | ||
|
||
Starts project after `npm run build` | ||
4. Install dependencies: | ||
|
||
After that, you can open the project in... | ||
``` javascript | ||
http://localhost:3000 | ||
``` | ||
Or you can define a port in eviroment variables... | ||
``` javascript | ||
app.set('port',process.env.port || 3000); | ||
``` | ||
```bash | ||
npm install | ||
``` | ||
|
||
## Screenshots | ||
5. Start the dev server: | ||
|
||
- Fields validation | ||
<p align='center'> | ||
<img src='https://i.imgur.com/JQD2vth.png' alt='final-project-image'> | ||
</p> | ||
```bash | ||
npm run dev | ||
``` | ||
|
||
- Invalid password or email | ||
<p align='center'> | ||
<img src='https://i.imgur.com/B8Mzqk5.png' alt='final-project-image'> | ||
</p> | ||
Open [http://localhost:3000](http://localhost:3000) to view it in the browser. | ||
|
||
- Successful sign in | ||
<p align='center'> | ||
<img src='https://i.imgur.com/hJoFb4B.png' alt='final-project-image'> | ||
</p> | ||
6. To compile TypeScript to JavaScript and run the project: | ||
|
||
- Sending token on headers | ||
```bash | ||
npm run build && npm start | ||
``` | ||
|
||
<p align='center'> | ||
<img src='https://i.imgur.com/5r0cAo0.png' alt='final-project-image'> | ||
</p> | ||
## API Reference | ||
|
||
- Authorization | ||
#### Sign up or register | ||
|
||
<p align='center'> | ||
<img src='https://i.imgur.com/jcTFWIB.png' alt='final-project-image'> | ||
</p> | ||
```http | ||
POST /signup | ||
``` | ||
|
||
## Tutorials | ||
| Body | Type | Description | | ||
| :--------- | :------- | :------------------------------- | | ||
| `email` | `string` | **Required**. User email address | | ||
| `password` | `string` | **Required**. Account password | | ||
|
||
- [JsonWebTokens #1](https://www.youtube.com/watch?v=qckBlIfOnlA) | ||
- [JsonWebTokens #2](https://www.youtube.com/watch?v=mbsmsi7l3r4) | ||
- [JsonWebTokens #3](https://www.youtube.com/watch?v=7nafaH9SddU) | ||
- [Passport JWT Strategy Flow](https://www.youtube.com/watch?v=o6mSdG09yOU) | ||
#### Sign in or login | ||
|
||
## Explication | ||
```http | ||
POST /signin | ||
``` | ||
|
||
#### Route creation | ||
| Body | Type | Description | | ||
| :--------- | :------- | :------------------------------- | | ||
| `email` | `string` | **Required**. User email address | | ||
| `password` | `string` | **Required**. Account password | | ||
|
||
``` javascript | ||
import { Router } from 'express'; | ||
import { signIn, signUp } from '../controllers/user.controller'; | ||
```http | ||
GET /auth | ||
``` | ||
|
||
const router = Router(); | ||
| Headers | Type | Description | | ||
| :--------------- | :---- | :-------------------------------------------- | | ||
| `Authentication` | `JWT` | **Required**. Jwt gived on sign in or sign up | | ||
|
||
router.post('/signup',signUp); | ||
router.post('/signin', signIn); | ||
## Screenshots | ||
|
||
export default router; | ||
``` | ||
Basic input validation | ||
|
||
#### Route controller | ||
![Screenshot](https://i.imgur.com/JQD2vth.png) | ||
|
||
``` javascript | ||
router.get('/auth', passport.authenticate('jwt', {session: false}), (req, res) => { | ||
res.status(200).json({msg: "Auth route succeeded"}) | ||
}) | ||
``` | ||
Invalid password or email | ||
|
||
#### Create token | ||
![Screenshot](https://i.imgur.com/B8Mzqk5.png) | ||
|
||
``` javascript | ||
function createToken(user:Iuser) { | ||
return jwt.sign({id: user.id, email:user.email}, config.jwtSecret, { | ||
expiresIn: 86400 | ||
}) | ||
} | ||
``` | ||
Successful sign in | ||
|
||
Works in this way... With JWT obviously you can generate a token for authentication, a token have some public and private information. Public info is like the algorith used to sign token or the type of token, also included something called "payload" wich is content or body of token (this includes all data registered for token). | ||
![Screenshot](https://i.imgur.com/hJoFb4B.png) | ||
|
||
To generate a token we use a function from jwt moduled sign, passing a "payload" that is information of token, and a secret used to sign token. | ||
Sending token on headers | ||
|
||
Token is signed by a private key, and it is used to "decrypt" it and use to auth, passport takes his time in this, with passport-jwt we can use a function called passport.authenticate() and thats it. | ||
![Screenshot](https://i.imgur.com/5r0cAo0.png) | ||
|
||
Authorization | ||
|
||
## Architecture | ||
![Screenshot](https://i.imgur.com/jcTFWIB.png) | ||
|
||
- [MVC](https://si.ua.es/es/documentacion/asp-net-mvc-3/1-dia/modelo-vista-controlador-mvc.html) | ||
## Tech Stack | ||
|
||
## Modules used | ||
| Name | Description | | ||
| ---------------------------------------------------------- | ----------------------------------------------------------- | | ||
| [Node.js](https://nodejs.org/es/download/) | Business logic | | ||
| [MongoDB](https://www.mongodb.com/try/download/community) | Database | | ||
| [Express](https://expressjs.com/es/api.html) | HTTP Server | | ||
| [TypeScript](https://www.typescriptlang.org/) | JavaScript super-set to add static code analysis | | ||
| [JWT](https://jwt.io/) | Library to generate JWTs | | ||
| [Mongoose](https://mongoosejs.com/docs/api.html) | ODM (Object Data Modeling) | | ||
| [Passport JWT](https://www.npmjs.com/package/passport-jwt) | Passport strategy for authenticating with a JSON Web Token. | | ||
| [Bcrypt](https://www.npmjs.com/package/passport-jwt) | Passport strategy for authenticating with a JSON Web Token. | | ||
|
||
- [bcrypt](https://github.com/kelektiv/node.bcrypt.js) | ||
## Lessons Learned | ||
|
||
- [cors](https://github.com/expressjs/cors) | ||
### Route creation | ||
|
||
- [express](https://github.com/expressjs/express) | ||
```typescript | ||
import { Router } from "express"; | ||
import { signIn, signUp } from "../controllers/user.controller"; | ||
const router = Router(); | ||
router.post("/signup", signUp); | ||
router.post("/signin", signIn); | ||
export default router; | ||
``` | ||
### Route controller | ||
```typescript | ||
router.get( | ||
"/auth", | ||
passport.authenticate("jwt", { session: false }), | ||
(req, res) => { | ||
res.status(200).json({ msg: "Auth route succeeded" }); | ||
} | ||
); | ||
``` | ||
### Create token | ||
```typescript | ||
function createToken(user: Iuser) { | ||
return jwt.sign({ id: user.id, email: user.email }, config.jwtSecret, { | ||
expiresIn: 86400, | ||
}); | ||
} | ||
``` | ||
- [jsonwebtoken](https://github.com/auth0/node-jsonwebtoken) | ||
Works in this way... With JWT obviously you can generate a token for authentication, a token can hold public data in a stateless way. Public info is like the algorithm used to sign token or the type of token, also included something called "payload" which is content or body of token (this includes all data registered for token). | ||
- [mongoose](https://github.com/Automattic/mongoose) | ||
To generate a token we use a function from jwt module called sign, passing a "payload" that is information that token will save, and a secret used to sign the token. | ||
- [morgan](https://github.com/expressjs/morgan) | ||
Token is signed by a private key, and with the same key we can check if token is valid and use it to authenticate an user, passport takes his time in this, with passport-jwt we can use a function called passport.authenticate() which is a middleware that handles all the logic from getting the token from auth header to validate it and attach the token payload to the request object of express. | ||
- [passport](https://github.com/jaredhanson/passport) | ||
## Roadmap | ||
- [passport-jwt](https://github.com/mikenicholson/passport-jwt) | ||
- [x] App functionality | ||
- [ ] Testing | ||
- [ ] Hosting, domain, etc. | ||
- [ ] CI/CD |