supaapps-auth 1.1.0 → 1.2.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 CHANGED
@@ -59,6 +59,17 @@ Get login uri
59
59
  AuthManager.getInstance().getLoginWithGoogleUri()
60
60
  ```
61
61
 
62
+
63
+ - Log user out
64
+
65
+ ```ts
66
+ await authManager.logout();
67
+ // or
68
+ authManager.logout().then(() => {
69
+ // user is now logged out
70
+ })
71
+ ```
72
+
62
73
  - Validate access token
63
74
 
64
75
  ```typescript
@@ -8,10 +8,13 @@ export declare class AuthManager {
8
8
  static getInstance<T>(): AuthManager;
9
9
  private toBase64Url;
10
10
  private generatePKCEPair;
11
+ private refreshAccessToken;
12
+ private checkAccessToken;
11
13
  mustBeLoggedIn(): Promise<boolean>;
12
14
  getLoginWithGoogleUri(): string;
13
15
  isLoggedIn(): Promise<boolean>;
14
16
  getAccessToken(): Promise<string>;
15
17
  loginUsingPkce(code: any): Promise<void>;
18
+ logout(): Promise<void>;
16
19
  static validateToken(authServer: string, bearerToken: string): Promise<boolean>;
17
20
  }
@@ -48,6 +48,79 @@ class AuthManager {
48
48
  }
49
49
  return AuthManager.instance;
50
50
  }
51
+ refreshAccessToken() {
52
+ return __awaiter(this, void 0, void 0, function* () {
53
+ return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
54
+ try {
55
+ const refreshToken = localStorage.getItem('refresh_token');
56
+ if (!refreshToken) {
57
+ throw new Error('No refresh token found');
58
+ }
59
+ const decodedRefreshToken = JSON.parse(atob(refreshToken.split('.')[1]));
60
+ if (decodedRefreshToken) {
61
+ const currentTime = Date.now() / 1000;
62
+ if (decodedRefreshToken.exp < currentTime) {
63
+ throw new Error('Refresh token expired');
64
+ }
65
+ }
66
+ yield fetch(`${this.authServer}auth/refresh`, {
67
+ method: 'POST',
68
+ headers: {
69
+ 'Content-Type': 'application/json',
70
+ },
71
+ body: JSON.stringify({
72
+ refresh_token: refreshToken,
73
+ }),
74
+ })
75
+ .then((response) => {
76
+ if (response.status !== 200) {
77
+ throw new Error('Failed to refresh the token');
78
+ }
79
+ return response.json();
80
+ })
81
+ .then((exchangeJson) => {
82
+ localStorage.setItem('refresh_token', exchangeJson.refresh_token);
83
+ localStorage.setItem('access_token', exchangeJson.access_token);
84
+ resolve(exchangeJson.access_token);
85
+ })
86
+ .catch((error) => {
87
+ reject(error);
88
+ });
89
+ }
90
+ catch (error) {
91
+ reject(error);
92
+ }
93
+ }));
94
+ });
95
+ }
96
+ checkAccessToken() {
97
+ return __awaiter(this, void 0, void 0, function* () {
98
+ return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
99
+ try {
100
+ const accessToken = localStorage.getItem('access_token');
101
+ if (!accessToken) {
102
+ throw new Error('No access token found');
103
+ }
104
+ // decode access token and check if it's expired
105
+ const decodedToken = accessToken
106
+ ? JSON.parse(atob(accessToken.split('.')[1]))
107
+ : null;
108
+ if (decodedToken) {
109
+ const currentTime = Date.now() / 1000;
110
+ if (decodedToken.exp < currentTime) {
111
+ // refreshing expired token
112
+ const newAccessToken = yield this.refreshAccessToken();
113
+ return resolve(newAccessToken);
114
+ }
115
+ }
116
+ resolve(accessToken);
117
+ }
118
+ catch (error) {
119
+ reject(error);
120
+ }
121
+ }));
122
+ });
123
+ }
51
124
  mustBeLoggedIn() {
52
125
  return __awaiter(this, void 0, void 0, function* () {
53
126
  return new Promise((resolve, reject) => {
@@ -76,56 +149,30 @@ class AuthManager {
76
149
  isLoggedIn() {
77
150
  return __awaiter(this, void 0, void 0, function* () {
78
151
  // todo here: check if refresh token is expired and if so, try to refresh, then update token
79
- return new Promise((resolve, reject) => {
152
+ return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
80
153
  try {
81
- const accessToken = localStorage.getItem('access_token');
82
- if (!accessToken) {
83
- return resolve(false);
84
- }
85
- // decode access token and check if it's expired
86
- const decodedToken = accessToken ? JSON.parse(atob(accessToken.split('.')[1])) : null;
87
- if (decodedToken) {
88
- const currentTime = Date.now() / 1000;
89
- if (decodedToken.exp < currentTime) {
90
- // add refresh check here instead and
91
- localStorage.removeItem('access_token');
92
- return resolve(false);
93
- }
94
- }
154
+ yield this.checkAccessToken();
95
155
  return resolve(true);
96
156
  }
97
157
  catch (error) {
98
158
  reject(error);
99
159
  }
100
- });
160
+ }));
101
161
  });
102
162
  }
103
163
  getAccessToken() {
104
164
  return __awaiter(this, void 0, void 0, function* () {
105
165
  // todo here: check if refresh token is expired and if so, try to refresh, then update token
106
166
  // otherwise throw error
107
- return new Promise((resolve, reject) => {
167
+ return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
108
168
  try {
109
- const accessToken = localStorage.getItem('access_token');
110
- if (!accessToken) {
111
- throw new Error('No access token found');
112
- }
113
- // decode access token and check if it's expired
114
- const decodedToken = accessToken ? JSON.parse(atob(accessToken.split('.')[1])) : null;
115
- if (decodedToken) {
116
- const currentTime = Date.now() / 1000;
117
- if (decodedToken.exp < currentTime) {
118
- // add refresh check here instead and
119
- localStorage.removeItem('access_token');
120
- throw new Error('Access token expired');
121
- }
122
- }
169
+ const accessToken = yield this.checkAccessToken();
123
170
  return resolve(accessToken);
124
171
  }
125
172
  catch (error) {
126
173
  reject(error);
127
174
  }
128
- });
175
+ }));
129
176
  });
130
177
  }
131
178
  loginUsingPkce(code) {
@@ -172,6 +219,34 @@ class AuthManager {
172
219
  });
173
220
  });
174
221
  }
222
+ logout() {
223
+ return __awaiter(this, void 0, void 0, function* () {
224
+ return new Promise((resolve, reject) => {
225
+ try {
226
+ const bearerToken = localStorage.getItem('access_token');
227
+ localStorage.removeItem('access_token');
228
+ localStorage.removeItem('refresh_token');
229
+ fetch(`${this.authServer}auth/logout`, {
230
+ method: 'POST',
231
+ headers: {
232
+ 'Content-Type': 'application/json',
233
+ 'Authorization': `Bearer ${bearerToken}`,
234
+ },
235
+ }).then((response) => {
236
+ if (response.status !== 200) {
237
+ throw new Error('Failed to attempt logout');
238
+ }
239
+ resolve();
240
+ }).catch((error) => {
241
+ reject(error);
242
+ });
243
+ }
244
+ catch (error) {
245
+ reject(error);
246
+ }
247
+ });
248
+ });
249
+ }
175
250
  static validateToken(authServer, bearerToken) {
176
251
  return __awaiter(this, void 0, void 0, function* () {
177
252
  return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "supaapps-auth",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,7 +1,6 @@
1
1
  import axios from 'axios';
2
2
  import { createHash, randomBytes } from 'crypto';
3
3
 
4
-
5
4
  export class AuthManager {
6
5
  private static instance: AuthManager | null = null;
7
6
  private readonly authServer: string | null = null;
@@ -50,6 +49,74 @@ export class AuthManager {
50
49
  return { newCodeVerifier, newCodeChallenge };
51
50
  };
52
51
 
52
+ private async refreshAccessToken(): Promise<string> {
53
+ return new Promise(async (resolve, reject) => {
54
+ try {
55
+ const refreshToken: string | null = localStorage.getItem('refresh_token');
56
+ if (!refreshToken) {
57
+ throw new Error('No refresh token found');
58
+ }
59
+ const decodedRefreshToken = JSON.parse(atob(refreshToken.split('.')[1]));
60
+ if (decodedRefreshToken) {
61
+ const currentTime = Date.now() / 1000;
62
+ if (decodedRefreshToken.exp < currentTime) {
63
+ throw new Error('Refresh token expired');
64
+ }
65
+ }
66
+ await fetch(`${this.authServer}auth/refresh`, {
67
+ method: 'POST',
68
+ headers: {
69
+ 'Content-Type': 'application/json',
70
+ },
71
+ body: JSON.stringify({
72
+ refresh_token: refreshToken,
73
+ }),
74
+ })
75
+ .then((response) => {
76
+ if (response.status !== 200) {
77
+ throw new Error('Failed to refresh the token');
78
+ }
79
+ return response.json();
80
+ })
81
+ .then((exchangeJson) => {
82
+ localStorage.setItem('refresh_token', exchangeJson.refresh_token);
83
+ localStorage.setItem('access_token', exchangeJson.access_token);
84
+ resolve(exchangeJson.access_token);
85
+ })
86
+ .catch((error) => {
87
+ reject(error);
88
+ });
89
+ } catch (error) {
90
+ reject(error);
91
+ }
92
+ });
93
+ }
94
+ private async checkAccessToken(): Promise<string> {
95
+ return new Promise(async (resolve, reject) => {
96
+ try {
97
+ const accessToken: string | null = localStorage.getItem('access_token');
98
+ if (!accessToken) {
99
+ throw new Error('No access token found');
100
+ }
101
+ // decode access token and check if it's expired
102
+ const decodedToken = accessToken
103
+ ? JSON.parse(atob(accessToken.split('.')[1]))
104
+ : null;
105
+ if (decodedToken) {
106
+ const currentTime = Date.now() / 1000;
107
+ if (decodedToken.exp < currentTime) {
108
+ // refreshing expired token
109
+ const newAccessToken = await this.refreshAccessToken();
110
+ return resolve(newAccessToken);
111
+ }
112
+ }
113
+ resolve(accessToken);
114
+ } catch (error) {
115
+ reject(error);
116
+ }
117
+ })
118
+ }
119
+
53
120
  public async mustBeLoggedIn(): Promise<boolean> {
54
121
  return new Promise((resolve, reject) => {
55
122
  this.isLoggedIn().then((isLoggedIn) => {
@@ -75,25 +142,12 @@ export class AuthManager {
75
142
  `&redirect_uri=${encodeURIComponent(this.redirectUri)}&code_challenge=${codeChallenge}&code_challenge_method=S256`
76
143
  }
77
144
  }
145
+
78
146
  public async isLoggedIn(): Promise<boolean> {
79
147
  // todo here: check if refresh token is expired and if so, try to refresh, then update token
80
- return new Promise((resolve, reject) => {
148
+ return new Promise(async (resolve, reject) => {
81
149
  try {
82
- const accessToken: string | null = localStorage.getItem('access_token');
83
- if (!accessToken) {
84
- return resolve(false);
85
- }
86
- // decode access token and check if it's expired
87
- const decodedToken = accessToken ? JSON.parse(atob(accessToken.split('.')[1])) : null;
88
- if (decodedToken) {
89
- const currentTime = Date.now() / 1000;
90
- if (decodedToken.exp < currentTime) {
91
- // add refresh check here instead and
92
- localStorage.removeItem('access_token');
93
- return resolve(false);
94
- }
95
- }
96
-
150
+ await this.checkAccessToken();
97
151
  return resolve(true);
98
152
  } catch (error) {
99
153
  reject(error);
@@ -104,22 +158,9 @@ export class AuthManager {
104
158
  public async getAccessToken(): Promise<string> {
105
159
  // todo here: check if refresh token is expired and if so, try to refresh, then update token
106
160
  // otherwise throw error
107
- return new Promise((resolve, reject) => {
161
+ return new Promise(async (resolve, reject) => {
108
162
  try {
109
- const accessToken: string | null = localStorage.getItem('access_token');
110
- if (!accessToken) {
111
- throw new Error('No access token found');
112
- }
113
- // decode access token and check if it's expired
114
- const decodedToken = accessToken ? JSON.parse(atob(accessToken.split('.')[1])) : null;
115
- if (decodedToken) {
116
- const currentTime = Date.now() / 1000;
117
- if (decodedToken.exp < currentTime) {
118
- // add refresh check here instead and
119
- localStorage.removeItem('access_token');
120
- throw new Error('Access token expired');
121
- }
122
- }
163
+ const accessToken = await this.checkAccessToken();
123
164
 
124
165
  return resolve(accessToken);
125
166
  } catch (error) {
@@ -170,6 +211,32 @@ export class AuthManager {
170
211
  });
171
212
  }
172
213
 
214
+ public async logout(): Promise<void> {
215
+ return new Promise((resolve, reject) => {
216
+ try {
217
+ const bearerToken = localStorage.getItem('access_token');
218
+ localStorage.removeItem('access_token');
219
+ localStorage.removeItem('refresh_token');
220
+ fetch(`${this.authServer}auth/logout`, {
221
+ method: 'POST',
222
+ headers: {
223
+ 'Content-Type': 'application/json',
224
+ 'Authorization': `Bearer ${bearerToken}`,
225
+ },
226
+ }).then((response) => {
227
+ if (response.status !== 200) {
228
+ throw new Error('Failed to attempt logout')
229
+ }
230
+ resolve();
231
+ }).catch((error) => {
232
+ reject(error);
233
+ })
234
+ } catch (error) {
235
+ reject(error);
236
+ }
237
+ })
238
+ }
239
+
173
240
  public static async validateToken(authServer: string, bearerToken: string): Promise<boolean> {
174
241
  return new Promise<boolean>(async (resolve, reject) => {
175
242
  try {