Browse Source

feat(server): Add jwt secret to config

Michael Bromley 7 years ago
parent
commit
4d542e050b

+ 1 - 0
server/index-dev.ts

@@ -7,6 +7,7 @@ import { IntegerIdStrategy, StringIdStrategy } from './src/config/entity-id-stra
 bootstrap({
 bootstrap({
     port: 3000,
     port: 3000,
     cors: true,
     cors: true,
+    jwtSecret: 'some-secret',
     dbConnectionOptions: {
     dbConnectionOptions: {
         type: 'mysql',
         type: 'mysql',
         entities: ['./src/**/entity/**/*.entity.ts'],
         entities: ['./src/**/entity/**/*.entity.ts'],

+ 7 - 5
server/src/auth/auth.service.ts

@@ -3,16 +3,18 @@ import { InjectConnection } from '@nestjs/typeorm';
 import * as jwt from 'jsonwebtoken';
 import * as jwt from 'jsonwebtoken';
 import { Connection } from 'typeorm';
 import { Connection } from 'typeorm';
 import { User } from '../entity/user/user.entity';
 import { User } from '../entity/user/user.entity';
+import { ConfigService } from '../service/config.service';
 import { JwtPayload } from './auth-types';
 import { JwtPayload } from './auth-types';
 import { PasswordService } from './password.service';
 import { PasswordService } from './password.service';
 import { Role } from './role';
 import { Role } from './role';
 
 
-// TODO: make this configurable e.g. from environment
-export const JWT_SECRET = 'some_secret';
-
 @Injectable()
 @Injectable()
 export class AuthService {
 export class AuthService {
-    constructor(private passwordService: PasswordService, @InjectConnection() private connection: Connection) {}
+    constructor(
+        private passwordService: PasswordService,
+        @InjectConnection() private connection: Connection,
+        private configService: ConfigService,
+    ) {}
 
 
     async createToken(identifier: string, password: string): Promise<{ user: User; token: string }> {
     async createToken(identifier: string, password: string): Promise<{ user: User; token: string }> {
         const user = await this.connection.getRepository(User).findOne({
         const user = await this.connection.getRepository(User).findOne({
@@ -31,7 +33,7 @@ export class AuthService {
             throw new UnauthorizedException();
             throw new UnauthorizedException();
         }
         }
         const payload: JwtPayload = { identifier, roles: user.roles };
         const payload: JwtPayload = { identifier, roles: user.roles };
-        const token = jwt.sign(payload, JWT_SECRET, { expiresIn: 3600 });
+        const token = jwt.sign(payload, this.configService.jwtSecret, { expiresIn: 3600 });
 
 
         return { user, token };
         return { user, token };
     }
     }

+ 4 - 3
server/src/auth/jwt.strategy.ts

@@ -1,15 +1,16 @@
 import { Injectable, UnauthorizedException } from '@nestjs/common';
 import { Injectable, UnauthorizedException } from '@nestjs/common';
 import { PassportStrategy } from '@nestjs/passport';
 import { PassportStrategy } from '@nestjs/passport';
 import { ExtractJwt, Strategy } from 'passport-jwt';
 import { ExtractJwt, Strategy } from 'passport-jwt';
+import { ConfigService } from '../service/config.service';
 import { JwtPayload } from './auth-types';
 import { JwtPayload } from './auth-types';
-import { AuthService, JWT_SECRET } from './auth.service';
+import { AuthService } from './auth.service';
 
 
 @Injectable()
 @Injectable()
 export class JwtStrategy extends PassportStrategy(Strategy) {
 export class JwtStrategy extends PassportStrategy(Strategy) {
-    constructor(private readonly authService: AuthService) {
+    constructor(private readonly authService: AuthService, private configService: ConfigService) {
         super({
         super({
             jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
             jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
-            secretOrKey: JWT_SECRET,
+            secretOrKey: configService.jwtSecret,
         });
         });
     }
     }
 
 

+ 9 - 0
server/src/config/vendure-config.ts

@@ -23,6 +23,14 @@ export interface VendureConfig {
      * Which port the Vendure server should listen on.
      * Which port the Vendure server should listen on.
      */
      */
     port: number;
     port: number;
+    /**
+     * The secret used for signing each JWT used in authenticating users.
+     * In production applications, this should not be stored as a string in
+     * source control for security reasons, but may be loaded from an external
+     * file not under source control, or from an environment variable, for example.
+     * See https://stackoverflow.com/a/30090120/772859
+     */
+    jwtSecret: string;
     /**
     /**
      * Defines the strategy used for both storing the primary keys of entities
      * Defines the strategy used for both storing the primary keys of entities
      * in the database, and the encoding & decoding of those ids when exposing
      * in the database, and the encoding & decoding of those ids when exposing
@@ -40,6 +48,7 @@ const defaultConfig: VendureConfig = {
     defaultLanguageCode: LanguageCode.EN,
     defaultLanguageCode: LanguageCode.EN,
     port: 3000,
     port: 3000,
     cors: false,
     cors: false,
+    jwtSecret: 'secret',
     apiPath: '/api',
     apiPath: '/api',
     entityIdStrategy: new AutoIncrementIdStrategy(),
     entityIdStrategy: new AutoIncrementIdStrategy(),
     dbConnectionOptions: {
     dbConnectionOptions: {

+ 1 - 0
server/src/service/config.service.mock.ts

@@ -7,6 +7,7 @@ export class MockConfigService implements MockClass<ConfigService> {
     apiPath = 'api';
     apiPath = 'api';
     port = 3000;
     port = 3000;
     cors = false;
     cors = false;
+    jwtSecret = 'secret';
     defaultLanguageCode: jest.Mock<any>;
     defaultLanguageCode: jest.Mock<any>;
     entityIdStrategy = new MockIdStrategy();
     entityIdStrategy = new MockIdStrategy();
     dbConnectionOptions = {};
     dbConnectionOptions = {};

+ 4 - 0
server/src/service/config.service.ts

@@ -23,6 +23,10 @@ export class ConfigService implements VendureConfig {
         return this.activeConfig.cors;
         return this.activeConfig.cors;
     }
     }
 
 
+    get jwtSecret(): string {
+        return this.activeConfig.jwtSecret;
+    }
+
     get entityIdStrategy(): EntityIdStrategy {
     get entityIdStrategy(): EntityIdStrategy {
         return this.activeConfig.entityIdStrategy;
         return this.activeConfig.entityIdStrategy;
     }
     }