@rockyatoyan/nest-oauth 0.0.1 → 0.0.3
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 +102 -82
- package/dist/index.d.mts +75 -0
- package/dist/index.d.ts +75 -0
- package/dist/index.js +334 -0
- package/dist/index.mjs +334 -0
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,98 +1,118 @@
|
|
|
1
|
-
|
|
2
|
-
<a href="http://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo-small.svg" width="120" alt="Nest Logo" /></a>
|
|
3
|
-
</p>
|
|
4
|
-
|
|
5
|
-
[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456
|
|
6
|
-
[circleci-url]: https://circleci.com/gh/nestjs/nest
|
|
7
|
-
|
|
8
|
-
<p align="center">A progressive <a href="http://nodejs.org" target="_blank">Node.js</a> framework for building efficient and scalable server-side applications.</p>
|
|
9
|
-
<p align="center">
|
|
10
|
-
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/v/@nestjs/core.svg" alt="NPM Version" /></a>
|
|
11
|
-
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/l/@nestjs/core.svg" alt="Package License" /></a>
|
|
12
|
-
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/dm/@nestjs/common.svg" alt="NPM Downloads" /></a>
|
|
13
|
-
<a href="https://circleci.com/gh/nestjs/nest" target="_blank"><img src="https://img.shields.io/circleci/build/github/nestjs/nest/master" alt="CircleCI" /></a>
|
|
14
|
-
<a href="https://discord.gg/G7Qnnhy" target="_blank"><img src="https://img.shields.io/badge/discord-online-brightgreen.svg" alt="Discord"/></a>
|
|
15
|
-
<a href="https://opencollective.com/nest#backer" target="_blank"><img src="https://opencollective.com/nest/backers/badge.svg" alt="Backers on Open Collective" /></a>
|
|
16
|
-
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://opencollective.com/nest/sponsors/badge.svg" alt="Sponsors on Open Collective" /></a>
|
|
17
|
-
<a href="https://paypal.me/kamilmysliwiec" target="_blank"><img src="https://img.shields.io/badge/Donate-PayPal-ff3f59.svg" alt="Donate us"/></a>
|
|
18
|
-
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg" alt="Support us"></a>
|
|
19
|
-
<a href="https://twitter.com/nestframework" target="_blank"><img src="https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow" alt="Follow us on Twitter"></a>
|
|
20
|
-
</p>
|
|
21
|
-
<!--[](https://opencollective.com/nest#backer)
|
|
22
|
-
[](https://opencollective.com/nest#sponsor)-->
|
|
23
|
-
|
|
24
|
-
## Description
|
|
25
|
-
|
|
26
|
-
[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.
|
|
27
|
-
|
|
28
|
-
## Project setup
|
|
1
|
+
# @rockyatoyan/nest-oauth
|
|
29
2
|
|
|
30
|
-
|
|
31
|
-
$ npm install
|
|
32
|
-
```
|
|
3
|
+
Универсальный OAuth-модуль для **NestJS**, позволяющий легко подключать OAuth-провайдеров (Google, GitHub и др.) с единым API, минимальной конфигурацией и удобными декораторами.
|
|
33
4
|
|
|
34
|
-
|
|
5
|
+
---
|
|
35
6
|
|
|
36
|
-
|
|
37
|
-
# development
|
|
38
|
-
$ npm run start
|
|
7
|
+
## Возможности
|
|
39
8
|
|
|
40
|
-
|
|
41
|
-
|
|
9
|
+
- 🔐 Поддержка нескольких OAuth-провайдеров
|
|
10
|
+
- 🧩 Простое расширение через кастомные провайдеры
|
|
11
|
+
- ⚙️ Асинхронная регистрация модуля
|
|
12
|
+
- 🪝 Готовые декораторы для URL авторизации и callback
|
|
13
|
+
- 📦 Удобная интеграция с `@nestjs/config`
|
|
42
14
|
|
|
43
|
-
|
|
44
|
-
$ npm run start:prod
|
|
45
|
-
```
|
|
15
|
+
---
|
|
46
16
|
|
|
47
|
-
##
|
|
17
|
+
## Установка
|
|
48
18
|
|
|
49
19
|
```bash
|
|
50
|
-
|
|
51
|
-
$ npm run test
|
|
52
|
-
|
|
53
|
-
# e2e tests
|
|
54
|
-
$ npm run test:e2e
|
|
55
|
-
|
|
56
|
-
# test coverage
|
|
57
|
-
$ npm run test:cov
|
|
20
|
+
npm i @rockyatoyan/nest-oauth
|
|
58
21
|
```
|
|
59
22
|
|
|
60
|
-
##
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
23
|
+
## Регистрация модуля
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { ProviderModule } from '@rockyatoyan/nest-oauth';
|
|
27
|
+
import { ConfigModule, ConfigService } from '@nestjs/config';
|
|
28
|
+
|
|
29
|
+
ProviderModule.registerAsync({
|
|
30
|
+
imports: [ConfigModule],
|
|
31
|
+
inject: [ConfigService],
|
|
32
|
+
useFactory: (configService: ConfigService) => {
|
|
33
|
+
return {
|
|
34
|
+
baseUrl: configService.getOrThrow<string>(envNames.DOMAIN),
|
|
35
|
+
providers: [
|
|
36
|
+
new GoogleProvider({
|
|
37
|
+
clientId: configService.getOrThrow<string>(envNames.OAUTH_GOOGLE_CLIENT_ID),
|
|
38
|
+
clientSecret: configService.getOrThrow<string>(envNames.OAUTH_GOOGLE_CLIENT_SECRET),
|
|
39
|
+
}),
|
|
40
|
+
new GithubProvider({
|
|
41
|
+
clientId: configService.getOrThrow<string>(envNames.OAUTH_GITHUB_CLIENT_ID),
|
|
42
|
+
clientSecret: configService.getOrThrow<string>(envNames.OAUTH_GITHUB_CLIENT_SECRET),
|
|
43
|
+
}),
|
|
44
|
+
],
|
|
45
|
+
};
|
|
46
|
+
},
|
|
47
|
+
});
|
|
69
48
|
```
|
|
70
49
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
50
|
+
## Создание OAuth-провайдеров
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
import { BaseProvider, ProviderInstanceOptions, ExtractUserResponse } from '@rockyatoyan/nest-oauth';
|
|
54
|
+
|
|
55
|
+
interface GithubUserInfo {
|
|
56
|
+
id: number;
|
|
57
|
+
name: string;
|
|
58
|
+
avatar_url: string;
|
|
59
|
+
email: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export class GithubProvider extends BaseProvider {
|
|
63
|
+
constructor(options: ProviderInstanceOptions) {
|
|
64
|
+
super({
|
|
65
|
+
name: 'github',
|
|
66
|
+
clientId: options.clientId,
|
|
67
|
+
clientSecret: options.clientSecret,
|
|
68
|
+
scopes: ['user'],
|
|
69
|
+
authUrl: 'https://github.com/login/oauth/authorize',
|
|
70
|
+
tokensUrl: 'https://github.com/login/oauth/access_token',
|
|
71
|
+
userInfoUrl: 'https://api.github.com/user',
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
override extractUserInfo(data: GithubUserInfo): ExtractUserResponse {
|
|
76
|
+
return {
|
|
77
|
+
id: String(data.id),
|
|
78
|
+
avatarUrl: data.avatar_url,
|
|
79
|
+
email: data.email,
|
|
80
|
+
provider: this.options.name,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
89
85
|
|
|
90
|
-
##
|
|
86
|
+
## Использование
|
|
91
87
|
|
|
92
|
-
|
|
93
|
-
- Website - [https://nestjs.com](https://nestjs.com/)
|
|
94
|
-
- Twitter - [@nestframework](https://twitter.com/nestframework)
|
|
88
|
+
### Получение URL авторизации
|
|
95
89
|
|
|
96
|
-
|
|
90
|
+
```typescript
|
|
91
|
+
@OAuthUrl()
|
|
92
|
+
@Get('oauth/:provider/url')
|
|
93
|
+
async getOAuthProviderUrl() {}
|
|
94
|
+
```
|
|
97
95
|
|
|
98
|
-
|
|
96
|
+
### OAuth callback
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
@OAuthCallback()
|
|
100
|
+
@Get('oauth/:provider/callback')
|
|
101
|
+
async oauthCallback(
|
|
102
|
+
@Req() req: Request,
|
|
103
|
+
@Res({ passthrough: true }) res: Response,
|
|
104
|
+
) {
|
|
105
|
+
try {
|
|
106
|
+
await this.authService.loginWithOAuth(req, req.providerInfo!);
|
|
107
|
+
} catch (error) {
|
|
108
|
+
return res.redirect(
|
|
109
|
+
this.configService.get(envNames.CLIENT_ORIGIN) +
|
|
110
|
+
'/auth/login?error=true',
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return res.redirect(
|
|
115
|
+
this.configService.get(envNames.CLIENT_ORIGIN) + '/dashboard/profile',
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
```
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { FactoryProvider, ModuleMetadata, DynamicModule } from '@nestjs/common';
|
|
2
|
+
|
|
3
|
+
interface ProviderOptions {
|
|
4
|
+
name: string;
|
|
5
|
+
clientId: string;
|
|
6
|
+
clientSecret: string;
|
|
7
|
+
scopes: string[];
|
|
8
|
+
authUrl: string;
|
|
9
|
+
tokensUrl: string;
|
|
10
|
+
userInfoUrl: string;
|
|
11
|
+
}
|
|
12
|
+
type ProviderInstanceOptions = Pick<ProviderOptions, 'clientId' | 'clientSecret'>;
|
|
13
|
+
interface TokensResponse {
|
|
14
|
+
access_token: string;
|
|
15
|
+
refresh_token?: string;
|
|
16
|
+
expires_in?: number;
|
|
17
|
+
refresh_token_expires_in?: number;
|
|
18
|
+
}
|
|
19
|
+
interface ExtractUserResponse {
|
|
20
|
+
id: string;
|
|
21
|
+
avatarUrl: string;
|
|
22
|
+
email: string;
|
|
23
|
+
provider: string;
|
|
24
|
+
}
|
|
25
|
+
interface UserInfo extends ExtractUserResponse {
|
|
26
|
+
accessToken: string;
|
|
27
|
+
refreshToken?: string;
|
|
28
|
+
expiresIn?: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
declare module 'express-serve-static-core' {
|
|
32
|
+
interface Request {
|
|
33
|
+
providerInfo?: UserInfo;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
declare class BaseProvider {
|
|
38
|
+
protected readonly options: ProviderOptions;
|
|
39
|
+
BASE_URL: string;
|
|
40
|
+
constructor(options: ProviderOptions);
|
|
41
|
+
getAuthUrl(): string;
|
|
42
|
+
getRedirectUrl(): string;
|
|
43
|
+
extractUserInfo(data: any): ExtractUserResponse;
|
|
44
|
+
getUserFromCode(code: string): Promise<{
|
|
45
|
+
accessToken: string;
|
|
46
|
+
refreshToken: string | undefined;
|
|
47
|
+
expiresIn: number | undefined;
|
|
48
|
+
id: string;
|
|
49
|
+
avatarUrl: string;
|
|
50
|
+
email: string;
|
|
51
|
+
provider: string;
|
|
52
|
+
}>;
|
|
53
|
+
set BaseUrl(url: string);
|
|
54
|
+
get BaseUrl(): string;
|
|
55
|
+
get name(): string;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
interface ProviderModuleOptions {
|
|
59
|
+
baseUrl: string;
|
|
60
|
+
providers: BaseProvider[];
|
|
61
|
+
}
|
|
62
|
+
interface ProviderModuleAsyncOptions extends Omit<FactoryProvider<ProviderModuleOptions>, 'provide'> {
|
|
63
|
+
imports: ModuleMetadata['imports'];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
declare class ProviderModule {
|
|
67
|
+
static register(options: ProviderModuleOptions): DynamicModule;
|
|
68
|
+
static registerAsync(options: ProviderModuleAsyncOptions): DynamicModule;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
declare const OAuthUrl: () => <TFunction extends Function, Y>(target: TFunction | object, propertyKey?: string | symbol, descriptor?: TypedPropertyDescriptor<Y>) => void;
|
|
72
|
+
|
|
73
|
+
declare const OAuthCallback: () => <TFunction extends Function, Y>(target: TFunction | object, propertyKey?: string | symbol, descriptor?: TypedPropertyDescriptor<Y>) => void;
|
|
74
|
+
|
|
75
|
+
export { BaseProvider, type ExtractUserResponse, OAuthCallback, OAuthUrl, type ProviderInstanceOptions, ProviderModule, type ProviderOptions, type TokensResponse, type UserInfo };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { FactoryProvider, ModuleMetadata, DynamicModule } from '@nestjs/common';
|
|
2
|
+
|
|
3
|
+
interface ProviderOptions {
|
|
4
|
+
name: string;
|
|
5
|
+
clientId: string;
|
|
6
|
+
clientSecret: string;
|
|
7
|
+
scopes: string[];
|
|
8
|
+
authUrl: string;
|
|
9
|
+
tokensUrl: string;
|
|
10
|
+
userInfoUrl: string;
|
|
11
|
+
}
|
|
12
|
+
type ProviderInstanceOptions = Pick<ProviderOptions, 'clientId' | 'clientSecret'>;
|
|
13
|
+
interface TokensResponse {
|
|
14
|
+
access_token: string;
|
|
15
|
+
refresh_token?: string;
|
|
16
|
+
expires_in?: number;
|
|
17
|
+
refresh_token_expires_in?: number;
|
|
18
|
+
}
|
|
19
|
+
interface ExtractUserResponse {
|
|
20
|
+
id: string;
|
|
21
|
+
avatarUrl: string;
|
|
22
|
+
email: string;
|
|
23
|
+
provider: string;
|
|
24
|
+
}
|
|
25
|
+
interface UserInfo extends ExtractUserResponse {
|
|
26
|
+
accessToken: string;
|
|
27
|
+
refreshToken?: string;
|
|
28
|
+
expiresIn?: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
declare module 'express-serve-static-core' {
|
|
32
|
+
interface Request {
|
|
33
|
+
providerInfo?: UserInfo;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
declare class BaseProvider {
|
|
38
|
+
protected readonly options: ProviderOptions;
|
|
39
|
+
BASE_URL: string;
|
|
40
|
+
constructor(options: ProviderOptions);
|
|
41
|
+
getAuthUrl(): string;
|
|
42
|
+
getRedirectUrl(): string;
|
|
43
|
+
extractUserInfo(data: any): ExtractUserResponse;
|
|
44
|
+
getUserFromCode(code: string): Promise<{
|
|
45
|
+
accessToken: string;
|
|
46
|
+
refreshToken: string | undefined;
|
|
47
|
+
expiresIn: number | undefined;
|
|
48
|
+
id: string;
|
|
49
|
+
avatarUrl: string;
|
|
50
|
+
email: string;
|
|
51
|
+
provider: string;
|
|
52
|
+
}>;
|
|
53
|
+
set BaseUrl(url: string);
|
|
54
|
+
get BaseUrl(): string;
|
|
55
|
+
get name(): string;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
interface ProviderModuleOptions {
|
|
59
|
+
baseUrl: string;
|
|
60
|
+
providers: BaseProvider[];
|
|
61
|
+
}
|
|
62
|
+
interface ProviderModuleAsyncOptions extends Omit<FactoryProvider<ProviderModuleOptions>, 'provide'> {
|
|
63
|
+
imports: ModuleMetadata['imports'];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
declare class ProviderModule {
|
|
67
|
+
static register(options: ProviderModuleOptions): DynamicModule;
|
|
68
|
+
static registerAsync(options: ProviderModuleAsyncOptions): DynamicModule;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
declare const OAuthUrl: () => <TFunction extends Function, Y>(target: TFunction | object, propertyKey?: string | symbol, descriptor?: TypedPropertyDescriptor<Y>) => void;
|
|
72
|
+
|
|
73
|
+
declare const OAuthCallback: () => <TFunction extends Function, Y>(target: TFunction | object, propertyKey?: string | symbol, descriptor?: TypedPropertyDescriptor<Y>) => void;
|
|
74
|
+
|
|
75
|
+
export { BaseProvider, type ExtractUserResponse, OAuthCallback, OAuthUrl, type ProviderInstanceOptions, ProviderModule, type ProviderOptions, type TokensResponse, type UserInfo };
|