@dehwyyy/auth 1.0.2 → 1.0.4

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.
@@ -1,2 +1,2 @@
1
1
  import type { paths } from './schema';
2
- export declare const getClient: (app: string, baseUrl: string) => import("openapi-fetch").Client<paths, `${string}/${string}`>;
2
+ export declare const getClient: (app: string, baseUrl: string, redirectBaseUrl: string, redirectUriPrefix?: string) => import("openapi-fetch").Client<paths, `${string}/${string}`>;
@@ -1,13 +1,13 @@
1
1
  import createClient from 'openapi-fetch';
2
2
  import { Middleware } from './middleware';
3
3
  let client = null;
4
- export const getClient = (app, baseUrl) => {
4
+ export const getClient = (app, baseUrl, redirectBaseUrl, redirectUriPrefix = "") => {
5
5
  if (!client) {
6
6
  client = createClient({
7
7
  baseUrl,
8
8
  credentials: 'include',
9
9
  });
10
- const middleware = new Middleware(app, baseUrl);
10
+ const middleware = new Middleware(app, baseUrl, redirectBaseUrl, redirectUriPrefix);
11
11
  client.use(middleware.AuthorizationHeaderAttacher, middleware.TokenRefresher);
12
12
  }
13
13
  return client;
@@ -2,7 +2,9 @@ import type { Middleware as OpenAPIMiddleware } from 'openapi-fetch';
2
2
  export declare class Middleware {
3
3
  private app;
4
4
  private baseUrl;
5
- constructor(app: string, baseUrl: string);
5
+ private redirectBaseUrl;
6
+ private redirectUriPrefix;
7
+ constructor(app: string, baseUrl: string, redirectBaseUrl: string, redirectUriPrefix?: string);
6
8
  get AuthorizationHeaderAttacher(): OpenAPIMiddleware;
7
9
  get TokenRefresher(): OpenAPIMiddleware;
8
10
  }
@@ -2,15 +2,19 @@ import { GetAuthService } from '../index';
2
2
  export class Middleware {
3
3
  app;
4
4
  baseUrl;
5
- constructor(app, baseUrl) {
5
+ redirectBaseUrl;
6
+ redirectUriPrefix;
7
+ constructor(app, baseUrl, redirectBaseUrl, redirectUriPrefix = "") {
6
8
  this.app = app;
7
9
  this.baseUrl = baseUrl;
10
+ this.redirectBaseUrl = redirectBaseUrl;
11
+ this.redirectUriPrefix = redirectUriPrefix;
8
12
  }
9
13
  get AuthorizationHeaderAttacher() {
10
- const t = this;
14
+ const auth = GetAuthService(this.app, this.baseUrl, this.redirectBaseUrl, this.redirectUriPrefix);
11
15
  return {
12
16
  async onRequest({ request }) {
13
- return GetAuthService(t.app, t.baseUrl).WithAuthorizationToken(request);
17
+ return auth.WithAuthorizationToken(request);
14
18
  },
15
19
  };
16
20
  }
@@ -21,7 +25,8 @@ export class Middleware {
21
25
  if (response.status !== 401 || request.url.includes('/auth/refresh')) {
22
26
  return response;
23
27
  }
24
- return GetAuthService(t.app, t.baseUrl).RefreshAndRetry(request, response);
28
+ const auth = GetAuthService(t.app, t.baseUrl, t.redirectBaseUrl, t.redirectUriPrefix);
29
+ return auth.RefreshAndRetry(request, response);
25
30
  },
26
31
  };
27
32
  }
@@ -1,14 +1,11 @@
1
- interface Route {
2
- query: Record<string, unknown>;
3
- fullPath: string;
4
- }
5
- export declare class Guards {
6
- private app;
7
- private apiURL;
8
- private redirectBaseUrl;
9
- private redirectUriPrefix;
10
- constructor(app: string, apiURL: string, redirectBaseUrl: string, redirectUriPrefix?: string);
11
- private getLoginRedirectPath;
1
+ import { GetAuthService } from '../index';
2
+ import { Route } from '../types';
3
+ export declare class Guard {
4
+ private getAuthService;
5
+ private onUserRetrieve?;
6
+ constructor(getAuthService: () => ReturnType<typeof GetAuthService>, onUserRetrieve?: ((user: {
7
+ userId: string;
8
+ roles: string[];
9
+ }) => void) | undefined);
12
10
  Auth: (roles?: string[]) => (to: Route, from: Route) => Promise<string | true>;
13
11
  }
14
- export {};
@@ -1,57 +1,60 @@
1
1
  import { Storage, StorageKey } from '../client/storage/localStorage';
2
- import { GetAuthService } from '../index';
3
2
  let meCache = null;
4
3
  const ME_CACHE_TTL_MS = 15 * 1000;
5
4
  function arrayIntercept(arr1, arr2) {
6
5
  return arr1.filter((item) => arr2.includes(item));
7
6
  }
8
- export class Guards {
9
- app;
10
- apiURL;
11
- redirectBaseUrl;
12
- redirectUriPrefix;
13
- constructor(app, apiURL, redirectBaseUrl, redirectUriPrefix = "") {
14
- this.app = app;
15
- this.apiURL = apiURL;
16
- this.redirectBaseUrl = redirectBaseUrl;
17
- this.redirectUriPrefix = redirectUriPrefix;
18
- }
19
- getLoginRedirectPath(to, from) {
20
- const redirectUri = from.query['redirect_uri'] || encodeURIComponent(to.fullPath);
21
- const redirectPath = `${this.redirectBaseUrl}?redirect_uri=${this.redirectUriPrefix}${redirectUri}`;
22
- return redirectPath;
7
+ export class Guard {
8
+ getAuthService;
9
+ onUserRetrieve;
10
+ constructor(getAuthService, onUserRetrieve) {
11
+ this.getAuthService = getAuthService;
12
+ this.onUserRetrieve = onUserRetrieve;
23
13
  }
24
14
  Auth = (roles = []) => {
25
15
  return async (to, from) => {
26
- const loginRedirect = this.getLoginRedirectPath(to, from);
27
- const token = Storage.Get(StorageKey.ACCESS_TOKEN);
16
+ const auth = this.getAuthService();
17
+ const loginRedirect = auth.GetLoginRedirectPath(to, from);
18
+ let token = Storage.Get(StorageKey.ACCESS_TOKEN);
28
19
  if (!token) {
29
20
  if (roles.length === 0)
30
21
  return true;
31
- console.warn('Access denied');
32
- return loginRedirect;
22
+ // try to refresh
23
+ token = await auth.Refresh();
24
+ if (token) {
25
+ Storage.Set(StorageKey.ACCESS_TOKEN, token);
26
+ }
27
+ else {
28
+ return loginRedirect.redirect();
29
+ }
33
30
  }
34
31
  const now = Date.now();
35
32
  if (meCache && meCache.expiresAt > now) {
36
33
  const data = meCache.data;
37
34
  if (arrayIntercept(data.roles, roles).length === 0) {
38
- return loginRedirect;
35
+ return loginRedirect.redirect();
39
36
  }
40
37
  return true;
41
38
  }
42
- const response = await GetAuthService(this.app, this.apiURL).Validate();
39
+ const response = await auth.GetMe();
43
40
  if (!response) {
44
41
  console.warn('Access denied');
45
- return loginRedirect;
42
+ return loginRedirect.redirect();
46
43
  }
47
44
  meCache = { data: response, expiresAt: Date.now() + ME_CACHE_TTL_MS };
45
+ if (this.onUserRetrieve) {
46
+ this.onUserRetrieve({
47
+ userId: response.userId,
48
+ roles: response.roles,
49
+ });
50
+ }
48
51
  if (response.roles.length === 0) {
49
52
  console.warn('No roles found');
50
- return loginRedirect;
53
+ return loginRedirect.redirect();
51
54
  }
52
55
  if (arrayIntercept(response.roles, roles).length === 0) {
53
56
  console.warn('Access denied');
54
- return loginRedirect;
57
+ return loginRedirect.redirect();
55
58
  }
56
59
  return true;
57
60
  };
package/dist/index.d.ts CHANGED
@@ -1,22 +1,26 @@
1
- interface ValidateResponse {
2
- userId: string;
3
- roles: string[];
4
- }
1
+ import { GetMeResponse, Route } from './types';
5
2
  declare class AuthService {
6
3
  private app;
7
4
  private apiURL;
5
+ private redirectBaseUrl;
6
+ private redirectUriPrefix;
8
7
  private refreshPromise;
9
- constructor(app: string, apiURL: string);
10
- withApp(app: string): this;
8
+ constructor(app: string, apiURL: string, redirectBaseUrl: string, redirectUriPrefix?: string);
11
9
  private getClient;
12
10
  /**
13
11
  * @description Refresh access token
14
12
  * @returns `accessToken` -> refresh ok. `null` -> refresh failed
15
13
  **/
16
14
  private doRefresh;
17
- Validate(): Promise<ValidateResponse | null>;
15
+ withApp(app: string): this;
18
16
  WithAuthorizationToken(request: Request, token?: string | null): Request;
17
+ GetLoginRedirectPath(to: Route, from?: Route): {
18
+ redirect: () => string;
19
+ };
20
+ GetMe(verbose?: boolean): Promise<GetMeResponse | null>;
21
+ Logout(): Promise<boolean>;
22
+ Refresh(): Promise<string | null>;
19
23
  RefreshAndRetry(request: Request, response: Response): Promise<Response>;
20
24
  }
21
- export declare function GetAuthService(app: string, apiURL: string): AuthService;
25
+ export declare function GetAuthService(app: string, apiURL: string, redirectBaseUrl: string, redirectUriPrefix: string): AuthService;
22
26
  export {};
package/dist/index.js CHANGED
@@ -3,18 +3,18 @@ import { Storage, StorageKey } from './client/storage/localStorage';
3
3
  class AuthService {
4
4
  app;
5
5
  apiURL;
6
+ redirectBaseUrl;
7
+ redirectUriPrefix;
6
8
  // теперь обещание возвращает сам новый токен или null
7
9
  refreshPromise = null;
8
- constructor(app, apiURL) {
10
+ constructor(app, apiURL, redirectBaseUrl, redirectUriPrefix = "") {
9
11
  this.app = app;
10
12
  this.apiURL = apiURL;
11
- }
12
- withApp(app) {
13
- this.app = app;
14
- return this;
13
+ this.redirectBaseUrl = redirectBaseUrl;
14
+ this.redirectUriPrefix = redirectUriPrefix;
15
15
  }
16
16
  getClient() {
17
- return getClient(this.app, this.apiURL);
17
+ return getClient(this.app, this.apiURL, this.redirectBaseUrl, this.redirectUriPrefix);
18
18
  }
19
19
  /**
20
20
  * @description Refresh access token
@@ -34,16 +34,43 @@ class AuthService {
34
34
  Storage.Delete(StorageKey.ACCESS_TOKEN);
35
35
  return null;
36
36
  }
37
- // Validate token
38
- async Validate() {
39
- const token = Storage.Get(StorageKey.ACCESS_TOKEN);
37
+ withApp(app) {
38
+ this.app = app;
39
+ return this;
40
+ }
41
+ WithAuthorizationToken(request, token = null) {
42
+ token ??= Storage.Get(StorageKey.ACCESS_TOKEN);
43
+ if (token) {
44
+ request.headers.set('Authorization', `Bearer ${token}`);
45
+ }
46
+ return request;
47
+ }
48
+ GetLoginRedirectPath(to, from) {
49
+ const redirectUri = from?.query['redirect_uri'] || encodeURIComponent(to.fullPath);
50
+ const redirectPath = `${this.redirectBaseUrl}?redirect_uri=${this.redirectUriPrefix}${redirectUri}`;
51
+ return {
52
+ redirect: () => {
53
+ if (redirectPath.startsWith('http')) {
54
+ window.location.href = redirectPath;
55
+ return "";
56
+ }
57
+ return redirectPath;
58
+ }
59
+ };
60
+ }
61
+ async GetMe(verbose = false) {
62
+ let token = Storage.Get(StorageKey.ACCESS_TOKEN);
40
63
  if (!token) {
41
- return null;
64
+ token = await this.Refresh();
65
+ if (!token) {
66
+ return null;
67
+ }
42
68
  }
43
69
  const { response, data, error } = await this.getClient().GET('/auth/me', {
44
70
  params: {
45
71
  query: {
46
72
  app: this.app,
73
+ verbose: verbose ? 'all' : 'none',
47
74
  },
48
75
  header: {
49
76
  Authorization: `Bearer ${token}`,
@@ -61,14 +88,41 @@ class AuthService {
61
88
  return {
62
89
  userId: data.user_id,
63
90
  roles: data.roles || [],
91
+ active: data.active || false,
92
+ info: !data.info ? undefined : {
93
+ verified: data.info.verified || false,
94
+ username: data.info.username,
95
+ email: data.info.email,
96
+ avatar: data.info.avatar,
97
+ data: data.info.data,
98
+ },
64
99
  };
65
100
  }
66
- WithAuthorizationToken(request, token = null) {
67
- token ??= Storage.Get(StorageKey.ACCESS_TOKEN);
68
- if (token) {
69
- request.headers.set('Authorization', `Bearer ${token}`);
101
+ async Logout() {
102
+ Storage.Delete(StorageKey.ACCESS_TOKEN);
103
+ const { response, error } = await this.getClient().POST('/auth/logout');
104
+ if (error || !response.ok) {
105
+ console.error(error, response);
106
+ return false;
70
107
  }
71
- return request;
108
+ return true;
109
+ }
110
+ async Refresh() {
111
+ if (this.refreshPromise) {
112
+ return this.refreshPromise;
113
+ }
114
+ this.refreshPromise = this.doRefresh();
115
+ let token = null;
116
+ try {
117
+ token = await this.refreshPromise;
118
+ }
119
+ catch (e) {
120
+ console.error(e);
121
+ }
122
+ finally {
123
+ this.refreshPromise = null;
124
+ }
125
+ return token;
72
126
  }
73
127
  async RefreshAndRetry(request, response) {
74
128
  if (!this.refreshPromise) {
@@ -98,9 +152,9 @@ class AuthService {
98
152
  }
99
153
  }
100
154
  let auth = null;
101
- export function GetAuthService(app, apiURL) {
155
+ export function GetAuthService(app, apiURL, redirectBaseUrl, redirectUriPrefix) {
102
156
  if (!auth) {
103
- auth = new AuthService(app, apiURL);
157
+ auth = new AuthService(app, apiURL, redirectBaseUrl, redirectUriPrefix);
104
158
  }
105
159
  return auth.withApp(app);
106
160
  }
@@ -0,0 +1,16 @@
1
+ export interface GetMeResponse {
2
+ roles: string[];
3
+ userId: string;
4
+ active: boolean;
5
+ info?: {
6
+ verified: boolean;
7
+ avatar?: string;
8
+ data?: Record<string, unknown>;
9
+ email?: string;
10
+ username?: string;
11
+ };
12
+ }
13
+ export interface Route {
14
+ query: Record<string, unknown>;
15
+ fullPath: string;
16
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ ;
2
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dehwyyy/auth",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "private": false,
5
5
  "description": "dehwyyy auth utilities",
6
6
  "type": "module",