@ambushsoftworks/nestjs-auth-graphql 0.6.7 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +205 -2
- package/dist/auth.module.d.ts +12 -2
- package/dist/auth.module.d.ts.map +1 -1
- package/dist/auth.module.js +38 -0
- package/dist/auth.module.js.map +1 -1
- package/dist/constants.d.ts +1 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +2 -1
- package/dist/constants.js.map +1 -1
- package/dist/decorators/current-realm.decorator.d.ts +2 -0
- package/dist/decorators/current-realm.decorator.d.ts.map +1 -0
- package/dist/decorators/current-realm.decorator.js +10 -0
- package/dist/decorators/current-realm.decorator.js.map +1 -0
- package/dist/dto/jwt-payload.interface.d.ts +1 -0
- package/dist/dto/jwt-payload.interface.d.ts.map +1 -1
- package/dist/exceptions/invalid-auth-config.exception.d.ts +4 -0
- package/dist/exceptions/invalid-auth-config.exception.d.ts.map +1 -0
- package/dist/exceptions/invalid-auth-config.exception.js +12 -0
- package/dist/exceptions/invalid-auth-config.exception.js.map +1 -0
- package/dist/guards/tenant.guard.d.ts.map +1 -1
- package/dist/guards/tenant.guard.js +9 -1
- package/dist/guards/tenant.guard.js.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/interfaces/auth-logger.interface.d.ts +2 -0
- package/dist/interfaces/auth-logger.interface.d.ts.map +1 -1
- package/dist/interfaces/auth-logger.interface.js +2 -0
- package/dist/interfaces/auth-logger.interface.js.map +1 -1
- package/dist/interfaces/brute-force-repository.interface.d.ts +1 -0
- package/dist/interfaces/brute-force-repository.interface.d.ts.map +1 -1
- package/dist/interfaces/jwt-payload-factory.interface.d.ts +1 -0
- package/dist/interfaces/jwt-payload-factory.interface.d.ts.map +1 -1
- package/dist/interfaces/realm-extractor.interface.d.ts +4 -0
- package/dist/interfaces/realm-extractor.interface.d.ts.map +1 -0
- package/dist/interfaces/realm-extractor.interface.js +3 -0
- package/dist/interfaces/realm-extractor.interface.js.map +1 -0
- package/dist/interfaces/tenant-extractor.interface.d.ts +1 -1
- package/dist/interfaces/tenant-extractor.interface.d.ts.map +1 -1
- package/dist/interfaces/user-repository.interface.d.ts +6 -5
- package/dist/interfaces/user-repository.interface.d.ts.map +1 -1
- package/dist/middleware/realm.middleware.d.ts +9 -0
- package/dist/middleware/realm.middleware.d.ts.map +1 -0
- package/dist/middleware/realm.middleware.js +51 -0
- package/dist/middleware/realm.middleware.js.map +1 -0
- package/dist/repositories/noop-brute-force.repository.d.ts +1 -0
- package/dist/repositories/noop-brute-force.repository.d.ts.map +1 -1
- package/dist/repositories/noop-brute-force.repository.js +4 -0
- package/dist/repositories/noop-brute-force.repository.js.map +1 -1
- package/dist/resolvers/base-auth.resolver.d.ts +4 -3
- package/dist/resolvers/base-auth.resolver.d.ts.map +1 -1
- package/dist/resolvers/base-auth.resolver.js +24 -12
- package/dist/resolvers/base-auth.resolver.js.map +1 -1
- package/dist/resolvers/oauth.controller.d.ts.map +1 -1
- package/dist/resolvers/oauth.controller.js +7 -4
- package/dist/resolvers/oauth.controller.js.map +1 -1
- package/dist/services/auth.service.d.ts +16 -10
- package/dist/services/auth.service.d.ts.map +1 -1
- package/dist/services/auth.service.js +67 -48
- package/dist/services/auth.service.js.map +1 -1
- package/dist/services/brute-force-protection.service.d.ts +14 -7
- package/dist/services/brute-force-protection.service.d.ts.map +1 -1
- package/dist/services/brute-force-protection.service.js +68 -14
- package/dist/services/brute-force-protection.service.js.map +1 -1
- package/dist/services/default-jwt-payload-factory.d.ts +1 -0
- package/dist/services/default-jwt-payload-factory.d.ts.map +1 -1
- package/dist/services/default-jwt-payload-factory.js +5 -1
- package/dist/services/default-jwt-payload-factory.js.map +1 -1
- package/dist/services/verification.service.d.ts +7 -7
- package/dist/services/verification.service.d.ts.map +1 -1
- package/dist/services/verification.service.js +17 -17
- package/dist/services/verification.service.js.map +1 -1
- package/dist/strategies/jwt.strategy.d.ts +3 -1
- package/dist/strategies/jwt.strategy.d.ts.map +1 -1
- package/dist/strategies/jwt.strategy.js +10 -1
- package/dist/strategies/jwt.strategy.js.map +1 -1
- package/dist/test-utils/mock-repositories.d.ts.map +1 -1
- package/dist/test-utils/mock-repositories.js +1 -0
- package/dist/test-utils/mock-repositories.js.map +1 -1
- package/dist/utils/ip-hash.d.ts +2 -0
- package/dist/utils/ip-hash.d.ts.map +1 -0
- package/dist/utils/ip-hash.js +11 -0
- package/dist/utils/ip-hash.js.map +1 -0
- package/examples/full-resolver-template.ts +305 -0
- package/package.json +2 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Strategy } from 'passport-jwt';
|
|
2
|
+
import type { Request } from 'express';
|
|
2
3
|
import { AuthService } from '../services/auth.service';
|
|
3
4
|
import { JwtPayload } from '../dto/jwt-payload.interface';
|
|
4
5
|
import { IAuthUser } from '../interfaces/auth-user.interface';
|
|
@@ -10,8 +11,9 @@ export declare class JwtStrategy extends JwtStrategy_base {
|
|
|
10
11
|
private authService;
|
|
11
12
|
private readonly jwtValidation;
|
|
12
13
|
private readonly jwtPayloadFactory;
|
|
14
|
+
private readonly realmsEnabled;
|
|
13
15
|
constructor(options: AuthModuleOptions, authService: AuthService, jwtPayloadFactory?: IJwtPayloadFactory);
|
|
14
|
-
validate(payload: JwtPayload): Promise<IAuthUser | JwtPayloadUser>;
|
|
16
|
+
validate(req: Request, payload: JwtPayload): Promise<IAuthUser | JwtPayloadUser>;
|
|
15
17
|
}
|
|
16
18
|
export {};
|
|
17
19
|
//# sourceMappingURL=jwt.strategy.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jwt.strategy.d.ts","sourceRoot":"","sources":["../../src/strategies/jwt.strategy.ts"],"names":[],"mappings":"AAEA,OAAO,EAAc,QAAQ,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"jwt.strategy.d.ts","sourceRoot":"","sources":["../../src/strategies/jwt.strategy.ts"],"names":[],"mappings":"AAEA,OAAO,EAAc,QAAQ,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,6CAA6C,CAAC;AAGjF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;;AAelE,qBACa,WAAY,SAAQ,gBAA0B;IAOvD,OAAO,CAAC,WAAW;IANrB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA0B;IACxD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAqB;IACvD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAU;gBAGT,OAAO,EAAE,iBAAiB,EAC/C,WAAW,EAAE,WAAW,EAGhC,iBAAiB,CAAC,EAAE,kBAAkB;IA8BlC,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,GAAG,cAAc,CAAC;CAiCvF"}
|
|
@@ -42,12 +42,21 @@ let JwtStrategy = class JwtStrategy extends (0, passport_1.PassportStrategy)(pas
|
|
|
42
42
|
jwtFromRequest: jwtExtractor,
|
|
43
43
|
ignoreExpiration: false,
|
|
44
44
|
secretOrKey: options.jwtSecret,
|
|
45
|
+
passReqToCallback: true,
|
|
45
46
|
});
|
|
46
47
|
this.authService = authService;
|
|
47
48
|
this.jwtValidation = options.jwtValidation || 'full';
|
|
48
49
|
this.jwtPayloadFactory = jwtPayloadFactory || new default_jwt_payload_factory_1.DefaultJwtPayloadFactory();
|
|
50
|
+
this.realmsEnabled = !!options.realmExtractorInstance;
|
|
49
51
|
}
|
|
50
|
-
async validate(payload) {
|
|
52
|
+
async validate(req, payload) {
|
|
53
|
+
if (this.realmsEnabled) {
|
|
54
|
+
const requestRealm = req._realm;
|
|
55
|
+
const tokenRealm = payload.realm;
|
|
56
|
+
if (!tokenRealm || tokenRealm !== requestRealm) {
|
|
57
|
+
throw new common_1.UnauthorizedException('Invalid token');
|
|
58
|
+
}
|
|
59
|
+
}
|
|
51
60
|
const userId = this.jwtPayloadFactory.extractUserId(payload);
|
|
52
61
|
if (this.jwtValidation === 'payload-only') {
|
|
53
62
|
return { id: userId, email: payload.email };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jwt.strategy.js","sourceRoot":"","sources":["../../src/strategies/jwt.strategy.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAqF;AACrF,+CAAoD;AACpD,+CAAoD;AAEpD,2DAAuD;AAIvD,yFAAmF;AACnF,4CAAwE;AAQxE,SAAS,UAAU,CAAC,UAAkB;IACpC,OAAO,CAAC,GAAY,EAAiB,EAAE;QACrC,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;YAClD,OAAO,GAAG,CAAC,OAAO,CAAC,UAAU,CAAW,CAAC;QAC3C,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;AACJ,CAAC;AAGM,IAAM,WAAW,GAAjB,MAAM,WAAY,SAAQ,IAAA,2BAAgB,EAAC,uBAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"jwt.strategy.js","sourceRoot":"","sources":["../../src/strategies/jwt.strategy.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mock-repositories.d.ts","sourceRoot":"","sources":["../../src/test-utils/mock-repositories.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAM/I,wBAAgB,wBAAwB,IAAI,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,CAwCvE;AAKD,wBAAgB,gCAAgC,IAAI,IAAI,CAAC,MAAM,CAAC,uBAAuB,CAAC,CAYvF;AAKD,wBAAgB,gCAAgC,IAAI,IAAI,CAAC,MAAM,CAAC,uBAAuB,CAAC,CAOvF;AAKD,wBAAgB,8BAA8B,IAAI,IAAI,CAAC,MAAM,CAAC,qBAAqB,CAAC,
|
|
1
|
+
{"version":3,"file":"mock-repositories.d.ts","sourceRoot":"","sources":["../../src/test-utils/mock-repositories.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAM/I,wBAAgB,wBAAwB,IAAI,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,CAwCvE;AAKD,wBAAgB,gCAAgC,IAAI,IAAI,CAAC,MAAM,CAAC,uBAAuB,CAAC,CAYvF;AAKD,wBAAgB,gCAAgC,IAAI,IAAI,CAAC,MAAM,CAAC,uBAAuB,CAAC,CAOvF;AAKD,wBAAgB,8BAA8B,IAAI,IAAI,CAAC,MAAM,CAAC,qBAAqB,CAAC,CASnF;AAKD,wBAAgB,6BAA6B,IAAI,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAUjF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mock-repositories.js","sourceRoot":"","sources":["../../src/test-utils/mock-repositories.ts"],"names":[],"mappings":";;AAMA,4DAwCC;AAKD,4EAYC;AAKD,4EAOC;AAKD,
|
|
1
|
+
{"version":3,"file":"mock-repositories.js","sourceRoot":"","sources":["../../src/test-utils/mock-repositories.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ip-hash.d.ts","sourceRoot":"","sources":["../../src/utils/ip-hash.ts"],"names":[],"mappings":"AAgCA,wBAAgB,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAK9D"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.hashIp = hashIp;
|
|
4
|
+
const crypto_1 = require("crypto");
|
|
5
|
+
function hashIp(ipAddress, salt) {
|
|
6
|
+
return (0, crypto_1.createHmac)('sha256', salt)
|
|
7
|
+
.update(ipAddress)
|
|
8
|
+
.digest('hex')
|
|
9
|
+
.slice(0, 16);
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=ip-hash.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ip-hash.js","sourceRoot":"","sources":["../../src/utils/ip-hash.ts"],"names":[],"mappings":";;AAgCA,wBAKC;AArCD,mCAAoC;AAgCpC,SAAgB,MAAM,CAAC,SAAiB,EAAE,IAAY;IACpD,OAAO,IAAA,mBAAU,EAAC,QAAQ,EAAE,IAAI,CAAC;SAC9B,MAAM,CAAC,SAAS,CAAC;SACjB,MAAM,CAAC,KAAK,CAAC;SACb,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
//
|
|
3
|
+
// =============================================================================
|
|
4
|
+
// DO NOT IMPORT THIS FILE.
|
|
5
|
+
// =============================================================================
|
|
6
|
+
//
|
|
7
|
+
// This file is a REFERENCE TEMPLATE shipped with @ambushsoftworks/nestjs-auth-graphql.
|
|
8
|
+
// It is intentionally NOT exported from `src/index.ts` and is NOT importable by
|
|
9
|
+
// consumers from the package's barrel.
|
|
10
|
+
//
|
|
11
|
+
// WHY YOU CAN'T JUST IMPORT IT:
|
|
12
|
+
// TypeScript decorator metadata (the type information `@Mutation(() => Foo)`
|
|
13
|
+
// emits via `emitDecoratorMetadata`) is NOT preserved across compiled package
|
|
14
|
+
// boundaries. If this file's `@Mutation`/`@Query` decorators ran inside the
|
|
15
|
+
// package and the consumer imported the result, NestJS's GraphQL schema builder
|
|
16
|
+
// would throw "Cannot determine GraphQL output type" at runtime. The decorators
|
|
17
|
+
// MUST execute inside YOUR project's compilation unit. See the class-level
|
|
18
|
+
// docblock in `BaseAuthResolver` (`src/resolvers/base-auth.resolver.ts`) for
|
|
19
|
+
// the full explanation — this is the same constraint that prevents Item 5 of
|
|
20
|
+
// the Jobsites feature requests from being implementable inside the package.
|
|
21
|
+
//
|
|
22
|
+
// HOW TO USE THIS FILE:
|
|
23
|
+
// 1. Copy it into your own `src/resolvers/` directory and rename it to
|
|
24
|
+
// something like `auth.resolver.ts`.
|
|
25
|
+
// 2. Replace every `MyAuthUser`, `MyAuthResponse`, `MyLoginInput`, etc.
|
|
26
|
+
// placeholder with your project's actual GraphQL types (the placeholders
|
|
27
|
+
// are tagged with `// REPLACE:` comments).
|
|
28
|
+
// 3. Remove the `@ts-nocheck` directive at the top once you've wired in
|
|
29
|
+
// real types — it is only present so the template doesn't fail
|
|
30
|
+
// typechecking when the placeholders are undefined.
|
|
31
|
+
// 4. Register the resolver in your auth module's `providers` array.
|
|
32
|
+
//
|
|
33
|
+
// WHAT THIS TEMPLATE COVERS:
|
|
34
|
+
// Every `perform*` method on `BaseAuthResolver` is wrapped with the
|
|
35
|
+
// appropriate `@Mutation` or `@Query` decorator, plus the recommended
|
|
36
|
+
// `@Throttle` configuration on auth-sensitive endpoints (signup, login,
|
|
37
|
+
// password reset/change). Guards (`@UseGuards(JwtAuthGuard)`) are applied to
|
|
38
|
+
// methods that require an authenticated user.
|
|
39
|
+
//
|
|
40
|
+
// `@ts-nocheck` is used because the placeholder DTO/entity types intentionally
|
|
41
|
+
// don't exist in the package. Copy this file and replace placeholders before
|
|
42
|
+
// use; once your real types are wired in, remove the directive and the file
|
|
43
|
+
// will typecheck normally.
|
|
44
|
+
//
|
|
45
|
+
// =============================================================================
|
|
46
|
+
|
|
47
|
+
import { Resolver, Mutation, Query, Args, Context } from '@nestjs/graphql';
|
|
48
|
+
import { UseGuards } from '@nestjs/common';
|
|
49
|
+
import { Throttle } from '@nestjs/throttler';
|
|
50
|
+
import {
|
|
51
|
+
BaseAuthResolver,
|
|
52
|
+
JwtAuthGuard,
|
|
53
|
+
CurrentUser,
|
|
54
|
+
} from '@ambushsoftworks/nestjs-auth-graphql';
|
|
55
|
+
|
|
56
|
+
// REPLACE: import your project's User entity (must implement IAuthUser).
|
|
57
|
+
import { MyAuthUser } from '../entities/my-auth-user.entity';
|
|
58
|
+
|
|
59
|
+
// REPLACE: import your project's GraphQL ObjectType DTOs.
|
|
60
|
+
import { MyAuthResponse } from '../dto/my-auth-response.dto';
|
|
61
|
+
import { MyLogoutResponse } from '../dto/my-logout-response.dto';
|
|
62
|
+
import { MyLogoutAllResponse } from '../dto/my-logout-all-response.dto';
|
|
63
|
+
import { MyAccountLockStatus } from '../dto/my-account-lock-status.dto';
|
|
64
|
+
import { MyVerifyEmailResponse } from '../dto/my-verify-email-response.dto';
|
|
65
|
+
import { MyPhoneVerificationResponse } from '../dto/my-phone-verification-response.dto';
|
|
66
|
+
import { MyVerifyPhoneResponse } from '../dto/my-verify-phone-response.dto';
|
|
67
|
+
import { MyRemovePhoneResponse } from '../dto/my-remove-phone-response.dto';
|
|
68
|
+
import { MyPhoneVerificationStatus } from '../dto/my-phone-verification-status.dto';
|
|
69
|
+
import { MyPasswordResetResponse } from '../dto/my-password-reset-response.dto';
|
|
70
|
+
import { MyChangePasswordResponse } from '../dto/my-change-password-response.dto';
|
|
71
|
+
|
|
72
|
+
// REPLACE: import your project's GraphQL InputType DTOs.
|
|
73
|
+
import { MySignupInput } from '../dto/my-signup.input';
|
|
74
|
+
import { MyLoginInput } from '../dto/my-login.input';
|
|
75
|
+
import { MyRefreshTokenInput } from '../dto/my-refresh-token.input';
|
|
76
|
+
import { MyLogoutInput } from '../dto/my-logout.input';
|
|
77
|
+
import { MyVerifyEmailInput } from '../dto/my-verify-email.input';
|
|
78
|
+
import { MySendPhoneVerificationInput } from '../dto/my-send-phone-verification.input';
|
|
79
|
+
import { MyVerifyPhoneInput } from '../dto/my-verify-phone.input';
|
|
80
|
+
import { MyRequestPasswordResetInput } from '../dto/my-request-password-reset.input';
|
|
81
|
+
import { MyResetPasswordInput } from '../dto/my-reset-password.input';
|
|
82
|
+
import { MyChangePasswordInput } from '../dto/my-change-password.input';
|
|
83
|
+
import { MyCompleteFacebookSignUpInput } from '../dto/my-complete-facebook-signup.input';
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Full reference auth resolver. Wraps every `perform*` method on
|
|
87
|
+
* `BaseAuthResolver` with the matching GraphQL decorator. Copy and
|
|
88
|
+
* customize — DO NOT import this file from the package.
|
|
89
|
+
*/
|
|
90
|
+
@Resolver()
|
|
91
|
+
export class AuthResolver extends BaseAuthResolver<MyAuthUser> {
|
|
92
|
+
// ===========================================================================
|
|
93
|
+
// Core Auth Mutations
|
|
94
|
+
// ===========================================================================
|
|
95
|
+
|
|
96
|
+
@Mutation(() => MyAuthResponse)
|
|
97
|
+
@Throttle({ default: { limit: 5, ttl: 60000 } }) // 5 signups / minute / IP
|
|
98
|
+
async signup(
|
|
99
|
+
@Args('input') input: MySignupInput,
|
|
100
|
+
@Context() ctx: any,
|
|
101
|
+
): Promise<MyAuthResponse> {
|
|
102
|
+
return this.performSignup(input, ctx) as Promise<MyAuthResponse>;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
@Mutation(() => MyAuthResponse)
|
|
106
|
+
@Throttle({ default: { limit: 5, ttl: 60000 } }) // 5 logins / minute / IP
|
|
107
|
+
async login(
|
|
108
|
+
@Args('input') input: MyLoginInput,
|
|
109
|
+
@Context() ctx: any,
|
|
110
|
+
): Promise<MyAuthResponse> {
|
|
111
|
+
return this.performLogin(input, ctx) as Promise<MyAuthResponse>;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
@Mutation(() => MyAuthResponse)
|
|
115
|
+
async refreshToken(
|
|
116
|
+
@Args('input') input: MyRefreshTokenInput,
|
|
117
|
+
@Context() ctx: any,
|
|
118
|
+
): Promise<MyAuthResponse> {
|
|
119
|
+
return this.performRefreshToken(input, ctx) as Promise<MyAuthResponse>;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
@Mutation(() => MyLogoutResponse)
|
|
123
|
+
@UseGuards(JwtAuthGuard)
|
|
124
|
+
async logout(
|
|
125
|
+
@Args('input') input: MyLogoutInput,
|
|
126
|
+
@CurrentUser() user: MyAuthUser,
|
|
127
|
+
@Context() ctx: any,
|
|
128
|
+
): Promise<MyLogoutResponse> {
|
|
129
|
+
return this.performLogout(input, user, ctx);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
@Mutation(() => MyLogoutAllResponse)
|
|
133
|
+
@UseGuards(JwtAuthGuard)
|
|
134
|
+
async logoutAll(
|
|
135
|
+
@CurrentUser() user: MyAuthUser,
|
|
136
|
+
@Context() ctx: any,
|
|
137
|
+
): Promise<MyLogoutAllResponse> {
|
|
138
|
+
return this.performLogoutAll(user, ctx);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// ===========================================================================
|
|
142
|
+
// Account Lock Status
|
|
143
|
+
// ===========================================================================
|
|
144
|
+
|
|
145
|
+
@Query(() => MyAccountLockStatus)
|
|
146
|
+
async checkAccountLockStatus(
|
|
147
|
+
@Args('email') email: string,
|
|
148
|
+
): Promise<MyAccountLockStatus> {
|
|
149
|
+
return this.performCheckAccountLockStatus(email);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// ===========================================================================
|
|
153
|
+
// Email Verification
|
|
154
|
+
// ===========================================================================
|
|
155
|
+
|
|
156
|
+
@Mutation(() => MyVerifyEmailResponse)
|
|
157
|
+
async verifyEmail(
|
|
158
|
+
@Args('input') input: MyVerifyEmailInput,
|
|
159
|
+
@Context() ctx: any,
|
|
160
|
+
): Promise<MyVerifyEmailResponse> {
|
|
161
|
+
return this.performVerifyEmail(input, ctx);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
@Mutation(() => MyVerifyEmailResponse)
|
|
165
|
+
async resendVerificationEmail(
|
|
166
|
+
@Args('email') email: string,
|
|
167
|
+
@Context() ctx: any,
|
|
168
|
+
): Promise<MyVerifyEmailResponse> {
|
|
169
|
+
return this.performResendVerificationEmail(email, ctx);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// ===========================================================================
|
|
173
|
+
// Phone Verification
|
|
174
|
+
// ===========================================================================
|
|
175
|
+
|
|
176
|
+
@Mutation(() => MyPhoneVerificationResponse)
|
|
177
|
+
@UseGuards(JwtAuthGuard)
|
|
178
|
+
async sendPhoneVerification(
|
|
179
|
+
@Args('input') input: MySendPhoneVerificationInput,
|
|
180
|
+
@CurrentUser() user: MyAuthUser,
|
|
181
|
+
@Context() ctx: any,
|
|
182
|
+
): Promise<MyPhoneVerificationResponse> {
|
|
183
|
+
return this.performSendPhoneVerification(input, user, ctx);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
@Mutation(() => MyVerifyPhoneResponse)
|
|
187
|
+
@UseGuards(JwtAuthGuard)
|
|
188
|
+
async verifyPhone(
|
|
189
|
+
@Args('input') input: MyVerifyPhoneInput,
|
|
190
|
+
@CurrentUser() user: MyAuthUser,
|
|
191
|
+
): Promise<MyVerifyPhoneResponse> {
|
|
192
|
+
return this.performVerifyPhone(input, user);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
@Mutation(() => MyPhoneVerificationResponse)
|
|
196
|
+
@UseGuards(JwtAuthGuard)
|
|
197
|
+
async resendPhoneVerification(
|
|
198
|
+
@Args('phoneNumber') phoneNumber: string,
|
|
199
|
+
@CurrentUser() user: MyAuthUser,
|
|
200
|
+
): Promise<MyPhoneVerificationResponse> {
|
|
201
|
+
return this.performResendPhoneVerification(phoneNumber, user);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
@Mutation(() => MyRemovePhoneResponse)
|
|
205
|
+
@UseGuards(JwtAuthGuard)
|
|
206
|
+
async removePhoneNumber(
|
|
207
|
+
@CurrentUser() user: MyAuthUser,
|
|
208
|
+
): Promise<MyRemovePhoneResponse> {
|
|
209
|
+
return this.performRemovePhoneNumber(user);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
@Query(() => MyPhoneVerificationStatus)
|
|
213
|
+
@UseGuards(JwtAuthGuard)
|
|
214
|
+
async phoneVerificationStatus(
|
|
215
|
+
@CurrentUser() user: MyAuthUser,
|
|
216
|
+
): Promise<MyPhoneVerificationStatus> {
|
|
217
|
+
return this.performPhoneVerificationStatus(user);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// ===========================================================================
|
|
221
|
+
// Password Reset
|
|
222
|
+
// ===========================================================================
|
|
223
|
+
|
|
224
|
+
@Mutation(() => MyPasswordResetResponse)
|
|
225
|
+
@Throttle({ default: { limit: 3, ttl: 3600000 } }) // 3 requests / hour / IP
|
|
226
|
+
async requestPasswordReset(
|
|
227
|
+
@Args('input') input: MyRequestPasswordResetInput,
|
|
228
|
+
@Context() ctx: any,
|
|
229
|
+
): Promise<MyPasswordResetResponse> {
|
|
230
|
+
return this.performRequestPasswordReset(input, ctx);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
@Mutation(() => MyPasswordResetResponse)
|
|
234
|
+
@Throttle({ default: { limit: 5, ttl: 900000 } }) // 5 attempts / 15 min / IP
|
|
235
|
+
async resetPassword(
|
|
236
|
+
@Args('input') input: MyResetPasswordInput,
|
|
237
|
+
@Context() ctx: any,
|
|
238
|
+
): Promise<MyPasswordResetResponse> {
|
|
239
|
+
return this.performResetPassword(input, ctx);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// ===========================================================================
|
|
243
|
+
// Password Change (authenticated)
|
|
244
|
+
// ===========================================================================
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Change password for the authenticated user.
|
|
248
|
+
*
|
|
249
|
+
* `AuthService.changePassword` revokes ALL refresh tokens for the user
|
|
250
|
+
* (logging them out of every device including the current one). Calling
|
|
251
|
+
* `authService.issueAuthSession(user.id, ctx.res)` after the change keeps
|
|
252
|
+
* the current device logged in by minting a fresh token pair (and writing
|
|
253
|
+
* cookies if cookie auth is enabled).
|
|
254
|
+
*/
|
|
255
|
+
@Mutation(() => MyChangePasswordResponse)
|
|
256
|
+
@UseGuards(JwtAuthGuard)
|
|
257
|
+
@Throttle({ default: { limit: 5, ttl: 900000 } }) // 5 attempts / 15 min / IP
|
|
258
|
+
async changePassword(
|
|
259
|
+
@CurrentUser() user: MyAuthUser,
|
|
260
|
+
@Args('input') input: MyChangePasswordInput,
|
|
261
|
+
@Context() ctx: any,
|
|
262
|
+
): Promise<MyChangePasswordResponse> {
|
|
263
|
+
const result = await this.performChangePassword(
|
|
264
|
+
user.id,
|
|
265
|
+
input.currentPassword,
|
|
266
|
+
input.newPassword,
|
|
267
|
+
);
|
|
268
|
+
// Keep the current device logged in (other devices are revoked above).
|
|
269
|
+
// Use `getResponseFromContext` so cookies work under both Apollo
|
|
270
|
+
// (`ctx.res`) and Express/Fastify (`ctx.req.res`).
|
|
271
|
+
const res = this.getResponseFromContext(ctx);
|
|
272
|
+
const tokens = await this.authService.issueAuthSession(user.id, res);
|
|
273
|
+
return {
|
|
274
|
+
...result,
|
|
275
|
+
accessToken: tokens.accessToken,
|
|
276
|
+
refreshToken: tokens.refreshToken,
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// ===========================================================================
|
|
281
|
+
// Current User
|
|
282
|
+
// ===========================================================================
|
|
283
|
+
|
|
284
|
+
@Query(() => MyAuthUser)
|
|
285
|
+
@UseGuards(JwtAuthGuard)
|
|
286
|
+
async me(@CurrentUser() user: MyAuthUser): Promise<MyAuthUser> {
|
|
287
|
+
return this.performGetCurrentUser(user.id);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// ===========================================================================
|
|
291
|
+
// Facebook OAuth Email Fallback
|
|
292
|
+
// ===========================================================================
|
|
293
|
+
|
|
294
|
+
@Mutation(() => MyAuthResponse, {
|
|
295
|
+
name: 'completeFacebookSignUp',
|
|
296
|
+
description: 'Complete Facebook sign-up when email not provided by Facebook',
|
|
297
|
+
})
|
|
298
|
+
@Throttle({ default: { limit: 5, ttl: 60000 } })
|
|
299
|
+
async completeFacebookSignUp(
|
|
300
|
+
@Args('input') input: MyCompleteFacebookSignUpInput,
|
|
301
|
+
@Context() ctx: any,
|
|
302
|
+
): Promise<MyAuthResponse> {
|
|
303
|
+
return this.performCompleteFacebookSignUp(input, ctx) as Promise<MyAuthResponse>;
|
|
304
|
+
}
|
|
305
|
+
}
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ambushsoftworks/nestjs-auth-graphql",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Production-grade authentication package for NestJS with GraphQL, supporting JWT, OAuth, email/SMS verification, and biometric auth",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"files": [
|
|
8
8
|
"dist",
|
|
9
|
+
"examples",
|
|
9
10
|
"README.md",
|
|
10
11
|
"LICENSE"
|
|
11
12
|
],
|