├── .gitignore ├── .prettierrc ├── README.md ├── nodemon-debug.json ├── nodemon.json ├── package.json ├── src ├── app.controller.spec.ts ├── app.controller.ts ├── app.module.ts ├── app.service.ts ├── dummy.data.ts ├── main.ts ├── oauth │ ├── client.entity.ts │ ├── oauth-server │ │ ├── oauth-server.service.spec.ts │ │ └── oauth-server.service.ts │ ├── oauth.controller.spec.ts │ ├── oauth.controller.ts │ └── oauth.module.ts ├── site │ ├── site.controller.spec.ts │ ├── site.controller.ts │ └── site.module.ts ├── user │ ├── auth │ │ ├── auth.service.spec.ts │ │ └── auth.service.ts │ ├── local-strategy.ts │ ├── user.controller.spec.ts │ ├── user.controller.ts │ ├── user.dto.ts │ ├── user.entity.ts │ └── user.module.ts └── views │ ├── dialog.hbs │ ├── index.hbs │ ├── login-form.hbs │ └── partials │ └── layout.hbs ├── tsconfig.build.json ├── tsconfig.json ├── tsconfig.spec.json ├── tslint.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | node_modules/ 3 | 4 | # IDE 5 | /.idea 6 | /.awcache 7 | /.vscode 8 | 9 | # bundle 10 | packages/**/*.d.ts 11 | packages/**/*.js 12 | 13 | # misc 14 | .DS_Store 15 | lerna-debug.log 16 | npm-debug.log 17 | yarn-error.log 18 | /**/npm-debug.log 19 | /packages/**/.npmignore 20 | /packages/**/LICENSE 21 | 22 | # example 23 | /quick-start 24 | /example_dist 25 | /example 26 | 27 | # tests 28 | /test 29 | /coverage 30 | /.nyc_output 31 | build/config\.gypi 32 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all" 4 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Nest Logo 3 |

4 | 5 | [travis-image]: https://api.travis-ci.org/nestjs/nest.svg?branch=master 6 | [travis-url]: https://travis-ci.org/nestjs/nest 7 | [linux-image]: https://img.shields.io/travis/nestjs/nest/master.svg?label=linux 8 | [linux-url]: https://travis-ci.org/nestjs/nest 9 | 10 |

A progressive Node.js framework for building efficient and scalable server-side applications, heavily inspired by Angular.

11 |

12 | NPM Version 13 | Package License 14 | NPM Downloads 15 | Travis 16 | Linux 17 | Coverage 18 | Gitter 19 | Backers on Open Collective 20 | Sponsors on Open Collective 21 | 22 | 23 |

24 | 26 | 27 | ## Description 28 | 29 | [Nest](https://github.com/nestjs/nest) framework TypeScript starter repository. 30 | 31 | ## Installation 32 | 33 | ```bash 34 | $ npm install 35 | ``` 36 | 37 | ## Running the app 38 | 39 | ```bash 40 | # development 41 | $ npm run start 42 | 43 | # watch mode 44 | $ npm run start:dev 45 | 46 | # incremental rebuild (webpack) 47 | $ npm run webpack 48 | $ npm run start:hmr 49 | 50 | # production mode 51 | $ npm run start:prod 52 | ``` 53 | 54 | ## Test 55 | 56 | ```bash 57 | # unit tests 58 | $ npm run test 59 | 60 | # e2e tests 61 | $ npm run test:e2e 62 | 63 | # test coverage 64 | $ npm run test:cov 65 | ``` 66 | 67 | ## Support 68 | 69 | Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support). 70 | 71 | ## Stay in touch 72 | 73 | - Author - [Kamil Myśliwiec](https://kamilmysliwiec.com) 74 | - Website - [https://nestjs.com](https://nestjs.com/) 75 | - Twitter - [@nestframework](https://twitter.com/nestframework) 76 | 77 | ## License 78 | 79 | Nest is [MIT licensed](LICENSE). 80 | -------------------------------------------------------------------------------- /nodemon-debug.json: -------------------------------------------------------------------------------- 1 | { 2 | "watch": ["src"], 3 | "ext": "ts", 4 | "ignore": ["src/**/*.spec.ts"], 5 | "exec": "node --inspect-brk -r ts-node/register -r tsconfig-paths/register src/main.ts" 6 | } 7 | -------------------------------------------------------------------------------- /nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "watch": ["src"], 3 | "ext": "ts", 4 | "ignore": ["src/**/*.spec.ts"], 5 | "exec": "ts-node -r tsconfig-paths/register src/main.ts" 6 | } 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nestjs-oauth2orize", 3 | "version": "1.0.0", 4 | "description": "", 5 | "author": "", 6 | "license": "MIT", 7 | "scripts": { 8 | "build": "tsc -p tsconfig.build.json", 9 | "format": "prettier --write \"src/**/*.ts\"", 10 | "start": "ts-node -r tsconfig-paths/register src/main.ts", 11 | "start:dev": "nodemon", 12 | "start:debug": "nodemon --config nodemon-debug.json", 13 | "prestart:prod": "rimraf dist && tsc", 14 | "start:prod": "node dist/main.js", 15 | "lint": "tslint -p tsconfig.json -c tslint.json", 16 | "test": "jest", 17 | "test:watch": "jest --watch", 18 | "test:cov": "jest --coverage", 19 | "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", 20 | "test:e2e": "jest --config ./test/jest-e2e.json" 21 | }, 22 | "dependencies": { 23 | "@nestjs/common": "^5.4.0", 24 | "@nestjs/core": "^5.4.0", 25 | "@nestjs/passport": "^5.1.0", 26 | "@types/lodash": "^4.14.119", 27 | "connect-ensure-login": "^0.1.1", 28 | "cuid": "^2.1.4", 29 | "express-session": "^1.15.6", 30 | "hbs": "^4.0.1", 31 | "lodash": "^4.17.11", 32 | "oauth2orize": "^1.11.0", 33 | "passport": "^0.4.0", 34 | "passport-http": "^0.3.0", 35 | "passport-http-bearer": "^1.0.1", 36 | "passport-local": "^1.0.0", 37 | "passport-oauth2-client-password": "^0.1.2", 38 | "reflect-metadata": "^0.1.12", 39 | "rimraf": "^2.6.2", 40 | "rxjs": "^6.2.2", 41 | "typescript": "^3.0.1" 42 | }, 43 | "devDependencies": { 44 | "@nestjs/testing": "^5.1.0", 45 | "@types/connect-ensure-login": "^0.1.4", 46 | "@types/cuid": "^1.3.0", 47 | "@types/express": "^4.16.0", 48 | "@types/express-session": "^1.15.11", 49 | "@types/hbs": "^4.0.0", 50 | "@types/jest": "^23.3.1", 51 | "@types/node": "^10.7.1", 52 | "@types/oauth2orize": "^1.8.5", 53 | "@types/passport": "^0.4.0", 54 | "@types/passport-http": "^0.3.0", 55 | "@types/passport-http-bearer": "^1.0.1", 56 | "@types/passport-local": "^1.0.0", 57 | "@types/passport-oauth2-client-password": "^0.1.2", 58 | "@types/supertest": "^2.0.5", 59 | "jest": "^23.5.0", 60 | "nodemon": "^1.18.3", 61 | "prettier": "^1.14.2", 62 | "supertest": "^3.1.0", 63 | "ts-jest": "^23.1.3", 64 | "ts-loader": "^4.4.2", 65 | "ts-node": "^7.0.1", 66 | "tsconfig-paths": "^3.5.0", 67 | "tslint": "5.11.0" 68 | }, 69 | "jest": { 70 | "moduleFileExtensions": [ 71 | "js", 72 | "json", 73 | "ts" 74 | ], 75 | "rootDir": "src", 76 | "testRegex": ".spec.ts$", 77 | "transform": { 78 | "^.+\\.(t|j)s$": "ts-jest" 79 | }, 80 | "coverageDirectory": "../coverage", 81 | "testEnvironment": "node" 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/app.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { AppController } from './app.controller'; 3 | import { AppService } from './app.service'; 4 | 5 | describe('AppController', () => { 6 | let app: TestingModule; 7 | 8 | beforeAll(async () => { 9 | app = await Test.createTestingModule({ 10 | controllers: [AppController], 11 | providers: [AppService], 12 | }).compile(); 13 | }); 14 | 15 | describe('root', () => { 16 | it('should return "Hello World!"', () => { 17 | const appController = app.get(AppController); 18 | expect(appController.getHello()).toBe('Hello World!'); 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/app.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get } from '@nestjs/common'; 2 | import { AppService } from './app.service'; 3 | 4 | @Controller() 5 | export class AppController { 6 | constructor(private readonly appService: AppService) {} 7 | } 8 | -------------------------------------------------------------------------------- /src/app.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { AppController } from './app.controller'; 3 | import { AppService } from './app.service'; 4 | import { SiteModule } from './site/site.module'; 5 | import { UserModule } from './user/user.module'; 6 | import { OauthModule } from './oauth/oauth.module'; 7 | 8 | @Module({ 9 | imports: [SiteModule, UserModule, OauthModule], 10 | controllers: [AppController], 11 | providers: [AppService], 12 | }) 13 | export class AppModule {} 14 | -------------------------------------------------------------------------------- /src/app.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | 3 | @Injectable() 4 | export class AppService {} 5 | -------------------------------------------------------------------------------- /src/dummy.data.ts: -------------------------------------------------------------------------------- 1 | import { UserEntity } from './user/user.entity'; 2 | import { ClientEntity } from './oauth/client.entity'; 3 | 4 | export const DummyUserData: UserEntity = { 5 | username: 'bob', 6 | password: 'secret', 7 | }; 8 | 9 | export const DummyClient: ClientEntity = { 10 | clientId: 'abc123', 11 | clientSecret: null, 12 | name: 'dummy client', 13 | }; 14 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { NestFactory } from '@nestjs/core'; 2 | import { AppModule } from './app.module'; 3 | import { join } from 'path'; 4 | import * as hbs from 'hbs'; 5 | import * as passport from 'passport'; 6 | import * as session from 'express-session'; 7 | 8 | async function bootstrap() { 9 | const app = await NestFactory.create(AppModule); 10 | 11 | app.useStaticAssets(join(__dirname, 'public')); 12 | app.setBaseViewsDir(join(__dirname, 'views')); 13 | app.setViewEngine('hbs'); 14 | hbs.registerPartials(__dirname + '/views/partials'); 15 | 16 | app.use( 17 | session({ 18 | secret: 'some secret', 19 | }), 20 | ); 21 | app.use(passport.initialize()); 22 | app.use(passport.session()); 23 | passport.serializeUser((user, done) => { 24 | done(null, user); 25 | }); 26 | passport.deserializeUser((user, done) => { 27 | done(null, user); 28 | }); 29 | 30 | await app.listen(3000); 31 | } 32 | bootstrap(); 33 | -------------------------------------------------------------------------------- /src/oauth/client.entity.ts: -------------------------------------------------------------------------------- 1 | export class ClientEntity { 2 | clientId: string; 3 | clientSecret: string; 4 | name: string; 5 | } 6 | -------------------------------------------------------------------------------- /src/oauth/oauth-server/oauth-server.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { OauthServerService } from './oauth-server.service'; 3 | 4 | describe('OauthServerService', () => { 5 | let service: OauthServerService; 6 | 7 | beforeAll(async () => { 8 | const module: TestingModule = await Test.createTestingModule({ 9 | providers: [OauthServerService], 10 | }).compile(); 11 | service = module.get(OauthServerService); 12 | }); 13 | it('should be defined', () => { 14 | expect(service).toBeDefined(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/oauth/oauth-server/oauth-server.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, UnauthorizedException } from '@nestjs/common'; 2 | import * as oauth2orize from 'oauth2orize'; 3 | import { DummyClient } from 'src/dummy.data'; 4 | import { ClientEntity } from '../client.entity'; 5 | import * as cuid from 'cuid'; 6 | 7 | @Injectable() 8 | export class OauthServerService { 9 | server = oauth2orize.createServer(); 10 | // for faking DB operation 11 | grantCodes: { 12 | [key: string]: { clientId: string; redirectUri: string; username: string }; 13 | } = {}; 14 | accessTokens: { 15 | [key: string]: { clientId: string; username: string }; 16 | } = {}; 17 | 18 | constructor() { 19 | this.server.serializeClient((client: ClientEntity, done) => 20 | done(null, client.clientId), 21 | ); 22 | 23 | this.server.deserializeClient((id, done) => { 24 | if (id === DummyClient.clientId) { 25 | done(null, DummyClient); 26 | } 27 | done(new UnauthorizedException(`Invalid Client ID`)); 28 | }); 29 | 30 | // Grant authorization codes. The callback takes the `client` requesting 31 | // authorization, the `redirectUri` (which is used as a verifier in the 32 | // subsequent exchange), the authenticated `user` granting access, and 33 | // their response, which contains approved scope, duration, etc. as parsed by 34 | // the application. The application issues a code, which is bound to these 35 | // values, and will be exchanged for an access token. 36 | 37 | this.server.grant( 38 | oauth2orize.grant.code((client, redirectUri, user, ares, done) => { 39 | const code = cuid(); 40 | 41 | this.grantCodes[code] = { 42 | clientId: client.id, 43 | redirectUri, 44 | username: user.username, 45 | }; 46 | return done(null, code); 47 | }), 48 | ); 49 | 50 | // Exchange authorization codes for access tokens. The callback accepts the 51 | // `client`, which is exchanging `code` and any `redirectUri` from the 52 | // authorization request for verification. If these values are validated, the 53 | // application issues an access token on behalf of the user who authorized the 54 | // code. 55 | 56 | this.server.exchange( 57 | oauth2orize.exchange.code((client, code, redirectUri, done) => { 58 | const grantCode = this.grantCodes[code]; 59 | if (!grantCode) { 60 | return done(new UnauthorizedException('Invalid Grand Code')); 61 | } 62 | if (client.id !== grantCode.clientId) { 63 | return done(null, false); 64 | } 65 | if (redirectUri !== grantCode.redirectUri) { 66 | return done(null, false); 67 | } 68 | 69 | const token = cuid(); 70 | this.accessTokens[token] = { 71 | username: grantCode.username, 72 | clientId: client.id, 73 | }; 74 | return done(null, token); 75 | }), 76 | ); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/oauth/oauth.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { OauthController } from './oauth.controller'; 3 | 4 | describe('Oauth Controller', () => { 5 | let module: TestingModule; 6 | 7 | beforeAll(async () => { 8 | module = await Test.createTestingModule({ 9 | controllers: [OauthController], 10 | }).compile(); 11 | }); 12 | it('should be defined', () => { 13 | const controller: OauthController = module.get(OauthController); 14 | expect(controller).toBeDefined(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/oauth/oauth.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get, Res, Req, Render, Post } from '@nestjs/common'; 2 | 3 | @Controller() 4 | export class OauthController { 5 | @Get('dialog/authorize') 6 | @Render('dialog') 7 | authorization(@Req() req, @Res() res) { 8 | return { 9 | transactionId: req.oauth2.transactionID, 10 | user: req.user, 11 | client: req.oauth2.client, 12 | }; 13 | } 14 | 15 | @Post('dialog/authorize/decision') 16 | decision() { 17 | return; 18 | } 19 | 20 | @Post('oauth/token') 21 | token() { 22 | return; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/oauth/oauth.module.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Module, 3 | MiddlewareConsumer, 4 | RequestMethod, 5 | UnauthorizedException, 6 | Logger, 7 | } from '@nestjs/common'; 8 | import { OauthServerService } from './oauth-server/oauth-server.service'; 9 | import { OauthController } from './oauth.controller'; 10 | import { ensureLoggedIn } from 'connect-ensure-login'; 11 | import { DummyClient } from 'src/dummy.data'; 12 | import { Request, Response } from 'express'; 13 | 14 | @Module({ 15 | providers: [OauthServerService], 16 | controllers: [OauthController], 17 | }) 18 | export class OauthModule { 19 | constructor(private oauthServerService: OauthServerService) {} 20 | 21 | configure(consumer: MiddlewareConsumer) { 22 | consumer 23 | .apply( 24 | ensureLoggedIn(), 25 | this.oauthServerService.server.authorization( 26 | (clientId, redirectUri, done) => { 27 | if (clientId === DummyClient.clientId) { 28 | return done(null, DummyClient, redirectUri); 29 | } 30 | return done(new UnauthorizedException('Invalid Client')); 31 | }, 32 | (client, user, done: any) => { 33 | // Check if grant request qualifies for immediate approval 34 | 35 | const accessToken: string = Object.keys( 36 | this.oauthServerService.accessTokens, 37 | ).find(token => { 38 | return ( 39 | this.oauthServerService.accessTokens[token].clientId === 40 | client.clientId && 41 | this.oauthServerService.accessTokens[token].username === 42 | user.username 43 | ); 44 | }); 45 | // Auto-approve 46 | if (accessToken) { 47 | return done(null, true); 48 | } 49 | 50 | // Otherwise ask user 51 | return done(null, false); 52 | }, 53 | ), 54 | ) 55 | .forRoutes({ path: 'dialog/authorize', method: RequestMethod.GET }); 56 | 57 | consumer 58 | .apply(ensureLoggedIn(), this.oauthServerService.server.decision()) 59 | .forRoutes({ 60 | path: 'dialog/authorize/decision', 61 | method: RequestMethod.POST, 62 | }); 63 | 64 | consumer 65 | .apply( 66 | (req: Request, res: Response, next) => { 67 | Logger.log(req.body, req.query); 68 | next(false); 69 | }, 70 | this.oauthServerService.server.token(), 71 | this.oauthServerService.server.errorHandler(), 72 | ) 73 | .forRoutes({ 74 | path: 'oauth/token', 75 | method: RequestMethod.POST, 76 | }); 77 | 78 | return; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/site/site.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { SiteController } from './site.controller'; 3 | 4 | describe('Site Controller', () => { 5 | let module: TestingModule; 6 | 7 | beforeAll(async () => { 8 | module = await Test.createTestingModule({ 9 | controllers: [SiteController], 10 | }).compile(); 11 | }); 12 | it('should be defined', () => { 13 | const controller: SiteController = module.get(SiteController); 14 | expect(controller).toBeDefined(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/site/site.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get, Post, Render, Query, Req, Res } from '@nestjs/common'; 2 | import { DummyUserData } from 'src/dummy.data'; 3 | import { Request, Response } from 'express'; 4 | 5 | @Controller() 6 | export class SiteController { 7 | @Get() 8 | @Render('index') 9 | index(@Req() req: Request): object { 10 | return { isLoggedIn: !!req.user }; 11 | } 12 | 13 | @Get('login') 14 | @Render('login-form') 15 | loginForm(@Query() query): object { 16 | const { error } = query; 17 | return { 18 | ...DummyUserData, 19 | error: error !== undefined, 20 | }; 21 | } 22 | 23 | @Post('login') 24 | login() { 25 | return; 26 | } 27 | 28 | @Get('logout') 29 | logout(@Req() req: Request, @Res() res: Response) { 30 | req.logout(); 31 | res.redirect('/'); 32 | } 33 | 34 | @Get('account') 35 | account() { 36 | return `a sample protected 'my account' page`; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/site/site.module.ts: -------------------------------------------------------------------------------- 1 | import { Module, MiddlewareConsumer, RequestMethod } from '@nestjs/common'; 2 | import { SiteController } from './site.controller'; 3 | import passport = require('passport'); 4 | import { ensureLoggedIn } from 'connect-ensure-login'; 5 | 6 | @Module({ 7 | controllers: [SiteController], 8 | }) 9 | export class SiteModule { 10 | configure(consumer: MiddlewareConsumer) { 11 | consumer 12 | .apply( 13 | passport.authenticate('local', { 14 | successReturnToOrRedirect: '/', 15 | failureRedirect: '/login?error', 16 | }), 17 | ) 18 | .forRoutes({ path: 'login', method: RequestMethod.POST }); 19 | 20 | consumer 21 | .apply(ensureLoggedIn()) 22 | .forRoutes({ path: 'account', method: RequestMethod.GET }); 23 | 24 | return; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/user/auth/auth.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { AuthService } from './auth.service'; 3 | 4 | describe('AuthService', () => { 5 | let service: AuthService; 6 | 7 | beforeAll(async () => { 8 | const module: TestingModule = await Test.createTestingModule({ 9 | providers: [AuthService], 10 | }).compile(); 11 | service = module.get(AuthService); 12 | }); 13 | it('should be defined', () => { 14 | expect(service).toBeDefined(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/user/auth/auth.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import { UserEntity } from '../user.entity'; 3 | import { UserDTO } from '../user.dto'; 4 | import { DummyUserData } from '../../dummy.data'; 5 | import * as _ from 'lodash'; 6 | 7 | @Injectable() 8 | export class AuthService { 9 | async validateUser(data: UserDTO): Promise { 10 | if (_.isEqual(DummyUserData, data)) { 11 | return DummyUserData; 12 | } 13 | return null; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/user/local-strategy.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, UnauthorizedException } from '@nestjs/common'; 2 | import { PassportStrategy } from '@nestjs/passport'; 3 | import { Strategy } from 'passport-local'; 4 | import { AuthService } from './auth/auth.service'; 5 | import { UserDTO } from './user.dto'; 6 | 7 | @Injectable() 8 | export class LocalStrategy extends PassportStrategy(Strategy) { 9 | constructor(private readonly authService: AuthService) { 10 | super(async (username, password, done) => { 11 | const data: UserDTO = { username, password }; 12 | const user = await this.authService.validateUser(data); 13 | 14 | if (!user) { 15 | return done(new UnauthorizedException(), user); 16 | } 17 | return done(null, user); 18 | }); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/user/user.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { UserController } from './user.controller'; 3 | 4 | describe('User Controller', () => { 5 | let module: TestingModule; 6 | 7 | beforeAll(async () => { 8 | module = await Test.createTestingModule({ 9 | controllers: [UserController], 10 | }).compile(); 11 | }); 12 | it('should be defined', () => { 13 | const controller: UserController = module.get( 14 | UserController, 15 | ); 16 | expect(controller).toBeDefined(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/user/user.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller } from '@nestjs/common'; 2 | 3 | @Controller('user') 4 | export class UserController {} 5 | -------------------------------------------------------------------------------- /src/user/user.dto.ts: -------------------------------------------------------------------------------- 1 | export class UserDTO { 2 | username: string; 3 | password: string; 4 | } 5 | -------------------------------------------------------------------------------- /src/user/user.entity.ts: -------------------------------------------------------------------------------- 1 | export class UserEntity { 2 | username: string; 3 | password: string; 4 | } 5 | -------------------------------------------------------------------------------- /src/user/user.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { UserController } from './user.controller'; 3 | import { LocalStrategy } from './local-strategy'; 4 | import { AuthService } from './auth/auth.service'; 5 | 6 | @Module({ 7 | controllers: [UserController], 8 | providers: [LocalStrategy, AuthService], 9 | }) 10 | export class UserModule {} 11 | -------------------------------------------------------------------------------- /src/views/dialog.hbs: -------------------------------------------------------------------------------- 1 |

Hi {{user.username}}!

2 |

3 | {{client.name}} is requesting access to your account.

4 |

Do you approve?

5 | 6 |
7 | 8 |
9 | 10 | 11 |
12 |
13 | -------------------------------------------------------------------------------- /src/views/index.hbs: -------------------------------------------------------------------------------- 1 | {{#> layout }} 2 |

Home Page

3 | {{#if isLoggedIn}} 4 |

You are logged in.

5 |

6 | logout 7 | {{else}} 8 |
9 | login 10 |
11 | {{/if}} 12 | {{/layout}} 13 | -------------------------------------------------------------------------------- /src/views/login-form.hbs: -------------------------------------------------------------------------------- 1 | {{#> layout }} 2 |
3 |
4 |
5 |
6 | 7 | 8 |
9 |
10 | 11 | 12 |
13 | 14 |
15 |
16 | {{#if error}} 17 |

Invalid Credentials

18 | {{/if}} 19 |
20 |
21 | For Demo: 22 |
23 | username: {{username}} 24 |
25 | password: {{password}} 26 |
27 |
28 |
29 | {{/layout}} 30 | -------------------------------------------------------------------------------- /src/views/partials/layout.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | My Oauth Server 6 | 7 | 8 | 9 | 10 | 12 | 14 | 15 | 16 | 17 |
18 |
19 | {{> @partial-block }} 20 |
21 |
22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["src/**/*"], 4 | "exclude": ["node_modules", "**/*.spec.ts"] 5 | } 6 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "declaration": true, 5 | "noImplicitAny": false, 6 | "removeComments": true, 7 | "noLib": false, 8 | "allowSyntheticDefaultImports": true, 9 | "emitDecoratorMetadata": true, 10 | "experimentalDecorators": true, 11 | "target": "es6", 12 | "sourceMap": true, 13 | "outDir": "./dist", 14 | "baseUrl": "./" 15 | }, 16 | "exclude": ["node_modules"] 17 | } 18 | -------------------------------------------------------------------------------- /tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "types": ["jest", "node"] 5 | }, 6 | "include": ["**/*.spec.ts", "**/*.d.ts"] 7 | } 8 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": ["tslint:recommended"], 4 | "jsRules": { 5 | "no-unused-expression": true 6 | }, 7 | "rules": { 8 | "quotemark": [true, "single"], 9 | "member-access": [false], 10 | "ordered-imports": [false], 11 | "max-line-length": [true, 150], 12 | "member-ordering": [false], 13 | "interface-name": [false], 14 | "arrow-parens": false, 15 | "object-literal-sort-keys": false 16 | }, 17 | "rulesDirectory": [] 18 | } 19 | --------------------------------------------------------------------------------