├── .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 |
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 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
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 |
13 |
--------------------------------------------------------------------------------
/src/views/index.hbs:
--------------------------------------------------------------------------------
1 | {{#> layout }}
2 | Home Page
3 | {{#if isLoggedIn}}
4 | You are logged in.
5 |
6 | logout
7 | {{else}}
8 |
11 | {{/if}}
12 | {{/layout}}
13 |
--------------------------------------------------------------------------------
/src/views/login-form.hbs:
--------------------------------------------------------------------------------
1 | {{#> layout }}
2 |
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 |
--------------------------------------------------------------------------------