@usync/oauth2 0.0.5 → 0.1.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/dist/index.js +121 -129
- package/dist/providers/microsoft.d.ts +1 -0
- package/dist/types.d.ts +13 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,43 +1,32 @@
|
|
|
1
|
-
import { nanoid as
|
|
2
|
-
const R = 1,
|
|
3
|
-
class
|
|
4
|
-
constructor(e,
|
|
5
|
-
super(
|
|
1
|
+
import { nanoid as U } from "nanoid";
|
|
2
|
+
const R = 1, a = 2, d = 3;
|
|
3
|
+
class i extends Error {
|
|
4
|
+
constructor(e, o) {
|
|
5
|
+
super(o || `OAuth2Error: code=${e}`), this.code = e;
|
|
6
6
|
}
|
|
7
7
|
}
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
let s = "", o = 0;
|
|
14
|
-
for (; o < i.length; ) {
|
|
15
|
-
let t = i[o++], c = i[o++], a = i[o++];
|
|
16
|
-
if (s += e[t >> 2], s += e[(t & 3) << 4 | (c || 0) >> 4], c == null || (s += e[(c & 15) << 2 | (a || 0) >> 6]), a == null)
|
|
17
|
-
break;
|
|
18
|
-
s += e[a & 63];
|
|
19
|
-
}
|
|
20
|
-
return s;
|
|
21
|
-
}
|
|
22
|
-
function O(i) {
|
|
23
|
-
return b(i, S(), !1);
|
|
8
|
+
function O(r) {
|
|
9
|
+
let e = "";
|
|
10
|
+
for (const o of r)
|
|
11
|
+
e += String.fromCharCode(o);
|
|
12
|
+
return btoa(e).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
24
13
|
}
|
|
25
14
|
function _() {
|
|
26
|
-
return
|
|
15
|
+
return U(8);
|
|
27
16
|
}
|
|
28
17
|
function k() {
|
|
29
|
-
return
|
|
18
|
+
return U(64);
|
|
30
19
|
}
|
|
31
|
-
async function u(
|
|
32
|
-
const e = "S256",
|
|
20
|
+
async function u(r) {
|
|
21
|
+
const e = "S256", o = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(r));
|
|
33
22
|
return {
|
|
34
|
-
codeChallenge: O(new Uint8Array(
|
|
23
|
+
codeChallenge: O(new Uint8Array(o)),
|
|
35
24
|
codeChallengeMethod: e
|
|
36
25
|
};
|
|
37
26
|
}
|
|
38
27
|
class w {
|
|
39
|
-
constructor(e,
|
|
40
|
-
this.options = e, this._accessToken = null, this._refreshToken = null,
|
|
28
|
+
constructor(e, o) {
|
|
29
|
+
this.options = e, this._accessToken = null, this._refreshToken = null, o && (this.setRefreshToken(o.refreshToken), this.setAccessToken(o.accessToken));
|
|
41
30
|
}
|
|
42
31
|
_getValidToken(e) {
|
|
43
32
|
return e && (!e.expiresAt || Date.now() < e.expiresAt) ? e.token : void 0;
|
|
@@ -49,14 +38,14 @@ class w {
|
|
|
49
38
|
this.setRefreshToken(e), this.options.onSetRefreshToken?.(e);
|
|
50
39
|
}
|
|
51
40
|
getAccessToken() {
|
|
52
|
-
if (!this._accessToken) throw new
|
|
41
|
+
if (!this._accessToken) throw new i(d);
|
|
53
42
|
const e = this._getValidToken(this._accessToken);
|
|
54
|
-
if (!e) throw new
|
|
43
|
+
if (!e) throw new i(R);
|
|
55
44
|
return e;
|
|
56
45
|
}
|
|
57
46
|
getRefreshToken() {
|
|
58
47
|
const e = this._getValidToken(this._refreshToken);
|
|
59
|
-
if (!e) throw new
|
|
48
|
+
if (!e) throw new i(d, "Invalid refresh token");
|
|
60
49
|
return e;
|
|
61
50
|
}
|
|
62
51
|
setAccessToken(e) {
|
|
@@ -66,51 +55,51 @@ class w {
|
|
|
66
55
|
this._refreshToken = e ?? null;
|
|
67
56
|
}
|
|
68
57
|
}
|
|
69
|
-
const
|
|
58
|
+
const b = "https://www.dropbox.com/oauth2/authorize", A = "https://api.dropbox.com/oauth2/token", T = class T extends w {
|
|
70
59
|
async buildAuthUrl() {
|
|
71
60
|
this.session = {
|
|
72
61
|
state: _(),
|
|
73
62
|
codeVerifier: k()
|
|
74
63
|
};
|
|
75
|
-
const { codeChallenge: e, codeChallengeMethod:
|
|
64
|
+
const { codeChallenge: e, codeChallengeMethod: o } = await u(
|
|
76
65
|
this.session.codeVerifier
|
|
77
|
-
), s = new URL(
|
|
66
|
+
), s = new URL(b);
|
|
78
67
|
return Object.entries({
|
|
79
68
|
client_id: this.options.clientId,
|
|
80
69
|
code_challenge: e,
|
|
81
|
-
code_challenge_method:
|
|
70
|
+
code_challenge_method: o,
|
|
82
71
|
redirect_uri: this.options.redirectUrl,
|
|
83
72
|
response_type: "code",
|
|
84
73
|
token_access_type: "offline",
|
|
85
74
|
scope: this.options.scope,
|
|
86
75
|
state: this.session.state
|
|
87
|
-
}).forEach(([
|
|
88
|
-
t && s.searchParams.set(
|
|
76
|
+
}).forEach(([n, t]) => {
|
|
77
|
+
t && s.searchParams.set(n, t);
|
|
89
78
|
}), s.href;
|
|
90
79
|
}
|
|
91
80
|
async finishAuth(e) {
|
|
92
81
|
if (!this.session || this.session.state !== e.searchParams.get("state"))
|
|
93
|
-
throw new
|
|
94
|
-
const
|
|
95
|
-
if (!
|
|
82
|
+
throw new i(a, "state doesn't match");
|
|
83
|
+
const o = e.searchParams.get("code");
|
|
84
|
+
if (!o) throw new i(a, "Invalid code");
|
|
96
85
|
const s = new URLSearchParams();
|
|
97
86
|
Object.entries({
|
|
98
87
|
client_id: this.options.clientId,
|
|
99
88
|
client_secret: this.options.clientSecret,
|
|
100
|
-
code:
|
|
89
|
+
code: o,
|
|
101
90
|
code_verifier: this.session.codeVerifier,
|
|
102
91
|
grant_type: "authorization_code",
|
|
103
92
|
redirect_uri: this.options.redirectUrl
|
|
104
|
-
}).forEach(([c,
|
|
105
|
-
s.append(c,
|
|
93
|
+
}).forEach(([c, h]) => {
|
|
94
|
+
h != null && s.append(c, h);
|
|
106
95
|
});
|
|
107
|
-
const
|
|
96
|
+
const n = await fetch(A, {
|
|
108
97
|
method: "POST",
|
|
109
98
|
body: s
|
|
110
|
-
}), t = await
|
|
111
|
-
if (!
|
|
99
|
+
}), t = await n.json();
|
|
100
|
+
if (!n.ok) throw { status: n.status, data: t };
|
|
112
101
|
if (!t.refresh_token)
|
|
113
|
-
throw new
|
|
102
|
+
throw new i(a, "Failed to get refresh_token");
|
|
114
103
|
return this._updateRefreshToken({
|
|
115
104
|
token: t.refresh_token,
|
|
116
105
|
scope: t.scope
|
|
@@ -120,77 +109,77 @@ const g = class g extends w {
|
|
|
120
109
|
}), t.access_token;
|
|
121
110
|
}
|
|
122
111
|
async refreshToken() {
|
|
123
|
-
const e = new URLSearchParams(),
|
|
112
|
+
const e = new URLSearchParams(), o = this.getRefreshToken();
|
|
124
113
|
Object.entries({
|
|
125
114
|
client_id: this.options.clientId,
|
|
126
115
|
client_secret: this.options.clientSecret,
|
|
127
116
|
grant_type: "refresh_token",
|
|
128
|
-
refresh_token:
|
|
117
|
+
refresh_token: o
|
|
129
118
|
}).forEach(([t, c]) => {
|
|
130
|
-
e.append(t, c);
|
|
119
|
+
c != null && e.append(t, c);
|
|
131
120
|
});
|
|
132
|
-
const s = await fetch(
|
|
121
|
+
const s = await fetch(A, {
|
|
133
122
|
method: "POST",
|
|
134
123
|
body: e
|
|
135
|
-
}),
|
|
136
|
-
if (!s.ok) throw { status: s.status, data:
|
|
124
|
+
}), n = await s.json();
|
|
125
|
+
if (!s.ok) throw { status: s.status, data: n };
|
|
137
126
|
return this._updateAccessToken({
|
|
138
|
-
token:
|
|
139
|
-
expiresAt: Date.now() +
|
|
140
|
-
}),
|
|
127
|
+
token: n.access_token,
|
|
128
|
+
expiresAt: Date.now() + n.expires_in * 1e3
|
|
129
|
+
}), n.access_token;
|
|
141
130
|
}
|
|
142
131
|
};
|
|
143
|
-
|
|
132
|
+
T.Scopes = {
|
|
144
133
|
account: "account_info.read"
|
|
145
134
|
};
|
|
146
|
-
let p =
|
|
147
|
-
const
|
|
135
|
+
let p = T;
|
|
136
|
+
const S = "https://accounts.google.com/o/oauth2/v2/auth", y = "https://oauth2.googleapis.com/token", g = class g extends w {
|
|
148
137
|
async buildAuthUrl() {
|
|
149
138
|
this.session = {
|
|
150
139
|
state: _(),
|
|
151
140
|
codeVerifier: k()
|
|
152
141
|
};
|
|
153
|
-
const { codeChallenge: e, codeChallengeMethod:
|
|
142
|
+
const { codeChallenge: e, codeChallengeMethod: o } = await u(
|
|
154
143
|
this.session.codeVerifier
|
|
155
|
-
), s = new URL(
|
|
144
|
+
), s = new URL(S);
|
|
156
145
|
return Object.entries({
|
|
157
146
|
access_type: "offline",
|
|
158
147
|
client_id: this.options.clientId,
|
|
159
148
|
code_challenge: e,
|
|
160
|
-
code_challenge_method:
|
|
149
|
+
code_challenge_method: o,
|
|
161
150
|
include_granted_scopes: "true",
|
|
162
151
|
prompt: "consent",
|
|
163
152
|
redirect_uri: this.options.redirectUrl,
|
|
164
153
|
response_type: "code",
|
|
165
154
|
scope: this.options.scope,
|
|
166
155
|
state: this.session.state
|
|
167
|
-
}).forEach(([
|
|
168
|
-
t && s.searchParams.set(
|
|
156
|
+
}).forEach(([n, t]) => {
|
|
157
|
+
t && s.searchParams.set(n, t);
|
|
169
158
|
}), s.href;
|
|
170
159
|
}
|
|
171
160
|
async finishAuth(e) {
|
|
172
161
|
if (!this.session || this.session.state !== e.searchParams.get("state"))
|
|
173
|
-
throw new
|
|
174
|
-
const
|
|
175
|
-
if (!
|
|
162
|
+
throw new i(a, "state doesn't match");
|
|
163
|
+
const o = e.searchParams.get("code");
|
|
164
|
+
if (!o) throw new i(a, "Invalid code");
|
|
176
165
|
const s = new URLSearchParams();
|
|
177
166
|
Object.entries({
|
|
178
167
|
client_id: this.options.clientId,
|
|
179
168
|
client_secret: this.options.clientSecret,
|
|
180
|
-
code:
|
|
169
|
+
code: o,
|
|
181
170
|
code_verifier: this.session.codeVerifier,
|
|
182
171
|
grant_type: "authorization_code",
|
|
183
172
|
redirect_uri: this.options.redirectUrl
|
|
184
|
-
}).forEach(([c,
|
|
185
|
-
s.append(c,
|
|
173
|
+
}).forEach(([c, h]) => {
|
|
174
|
+
h != null && s.append(c, h);
|
|
186
175
|
});
|
|
187
|
-
const
|
|
176
|
+
const n = await fetch(y, {
|
|
188
177
|
method: "POST",
|
|
189
178
|
body: s
|
|
190
|
-
}), t = await
|
|
191
|
-
if (!
|
|
179
|
+
}), t = await n.json();
|
|
180
|
+
if (!n.ok) throw { status: n.status, data: t };
|
|
192
181
|
if (!t.refresh_token)
|
|
193
|
-
throw new
|
|
182
|
+
throw new i(a, "Failed to get refresh_token");
|
|
194
183
|
return this._updateRefreshToken({
|
|
195
184
|
token: t.refresh_token,
|
|
196
185
|
scope: t.scope
|
|
@@ -200,79 +189,82 @@ const T = class T extends w {
|
|
|
200
189
|
}), t.access_token;
|
|
201
190
|
}
|
|
202
191
|
async refreshToken() {
|
|
203
|
-
const e = new URLSearchParams(),
|
|
192
|
+
const e = new URLSearchParams(), o = this.getRefreshToken();
|
|
204
193
|
Object.entries({
|
|
205
194
|
client_id: this.options.clientId,
|
|
206
195
|
client_secret: this.options.clientSecret,
|
|
207
196
|
grant_type: "refresh_token",
|
|
208
|
-
refresh_token:
|
|
197
|
+
refresh_token: o,
|
|
209
198
|
scope: this.options.scope
|
|
210
199
|
}).forEach(([t, c]) => {
|
|
211
200
|
c != null && e.append(t, c);
|
|
212
201
|
});
|
|
213
|
-
const s = await fetch(
|
|
202
|
+
const s = await fetch(y, {
|
|
214
203
|
method: "POST",
|
|
215
204
|
body: e
|
|
216
|
-
}),
|
|
217
|
-
if (!s.ok) throw { status: s.status, data:
|
|
205
|
+
}), n = await s.json();
|
|
206
|
+
if (!s.ok) throw { status: s.status, data: n };
|
|
218
207
|
return this._updateAccessToken({
|
|
219
|
-
token:
|
|
220
|
-
expiresAt: Date.now() +
|
|
221
|
-
}),
|
|
208
|
+
token: n.access_token,
|
|
209
|
+
expiresAt: Date.now() + n.expires_in * 1e3
|
|
210
|
+
}), n.access_token;
|
|
222
211
|
}
|
|
223
212
|
};
|
|
224
|
-
|
|
213
|
+
g.Scopes = {
|
|
225
214
|
account: "https://www.googleapis.com/auth/userinfo.profile",
|
|
226
215
|
"drive.appdata": "https://www.googleapis.com/auth/drive.appdata",
|
|
227
216
|
imap: "https://mail.google.com/"
|
|
228
217
|
};
|
|
229
|
-
let
|
|
218
|
+
let l = g;
|
|
230
219
|
const m = class m extends w {
|
|
220
|
+
oauth2Url(e) {
|
|
221
|
+
return `https://login.microsoftonline.com/${this.options.provider?.microsoft?.accountType ?? "common"}/oauth2/v2.0/${e}`;
|
|
222
|
+
}
|
|
231
223
|
async buildAuthUrl() {
|
|
232
224
|
this.session = {
|
|
233
225
|
state: _(),
|
|
234
226
|
codeVerifier: k()
|
|
235
227
|
};
|
|
236
|
-
const { codeChallenge: e, codeChallengeMethod:
|
|
228
|
+
const { codeChallenge: e, codeChallengeMethod: o } = await u(
|
|
237
229
|
this.session.codeVerifier
|
|
238
|
-
), s = new URL("
|
|
230
|
+
), s = new URL(this.oauth2Url("authorize"));
|
|
239
231
|
return Object.entries({
|
|
240
232
|
client_id: this.options.clientId,
|
|
241
233
|
code_challenge: e,
|
|
242
|
-
code_challenge_method:
|
|
234
|
+
code_challenge_method: o,
|
|
243
235
|
redirect_uri: this.options.redirectUrl,
|
|
244
236
|
response_mode: "query",
|
|
245
237
|
response_type: "code",
|
|
246
238
|
scope: this.options.scope,
|
|
247
239
|
state: this.session.state
|
|
248
|
-
}).forEach(([
|
|
249
|
-
t && s.searchParams.set(
|
|
240
|
+
}).forEach(([n, t]) => {
|
|
241
|
+
t && s.searchParams.set(n, t);
|
|
250
242
|
}), s.href;
|
|
251
243
|
}
|
|
252
244
|
async finishAuth(e) {
|
|
253
245
|
if (!this.session || this.session.state !== e.searchParams.get("state"))
|
|
254
|
-
throw new
|
|
255
|
-
const
|
|
256
|
-
if (!
|
|
246
|
+
throw new i(a, "state doesn't match");
|
|
247
|
+
const o = e.searchParams.get("code");
|
|
248
|
+
if (!o) throw new i(a, "Invalid code");
|
|
257
249
|
const s = new URLSearchParams();
|
|
258
250
|
Object.entries({
|
|
259
251
|
client_id: this.options.clientId,
|
|
260
252
|
client_secret: this.options.clientSecret,
|
|
261
|
-
code:
|
|
253
|
+
code: o,
|
|
262
254
|
code_verifier: this.session.codeVerifier,
|
|
263
255
|
grant_type: "authorization_code",
|
|
264
256
|
redirect_uri: this.options.redirectUrl,
|
|
265
257
|
scope: this.options.scope
|
|
266
|
-
}).forEach(([c,
|
|
267
|
-
|
|
258
|
+
}).forEach(([c, h]) => {
|
|
259
|
+
h != null && s.append(c, h);
|
|
268
260
|
});
|
|
269
|
-
const
|
|
261
|
+
const n = await fetch(this.oauth2Url("token"), {
|
|
270
262
|
method: "POST",
|
|
271
263
|
body: s
|
|
272
|
-
}), t = await
|
|
273
|
-
if (!
|
|
264
|
+
}), t = await n.json();
|
|
265
|
+
if (!n.ok) throw { status: n.status, data: t };
|
|
274
266
|
if (!t.refresh_token)
|
|
275
|
-
throw new
|
|
267
|
+
throw new i(a, "Failed to get refresh_token");
|
|
276
268
|
return this._updateRefreshToken({
|
|
277
269
|
token: t.refresh_token,
|
|
278
270
|
scope: t.scope
|
|
@@ -282,25 +274,25 @@ const m = class m extends w {
|
|
|
282
274
|
}), t.access_token;
|
|
283
275
|
}
|
|
284
276
|
async refreshToken() {
|
|
285
|
-
const e = new URLSearchParams(),
|
|
277
|
+
const e = new URLSearchParams(), o = this.getRefreshToken();
|
|
286
278
|
Object.entries({
|
|
287
279
|
client_id: this.options.clientId,
|
|
288
280
|
client_secret: this.options.clientSecret,
|
|
289
281
|
grant_type: "refresh_token",
|
|
290
|
-
refresh_token:
|
|
282
|
+
refresh_token: o,
|
|
291
283
|
scope: this.options.scope
|
|
292
284
|
}).forEach(([t, c]) => {
|
|
293
|
-
c && e.append(t, c);
|
|
285
|
+
c != null && e.append(t, c);
|
|
294
286
|
});
|
|
295
|
-
const s = await fetch("
|
|
287
|
+
const s = await fetch(this.oauth2Url("token"), {
|
|
296
288
|
method: "POST",
|
|
297
289
|
body: e
|
|
298
|
-
}),
|
|
299
|
-
if (!s.ok) throw { status: s.status, data:
|
|
290
|
+
}), n = await s.json();
|
|
291
|
+
if (!s.ok) throw { status: s.status, data: n };
|
|
300
292
|
return this._updateAccessToken({
|
|
301
|
-
token:
|
|
302
|
-
expiresAt: Date.now() +
|
|
303
|
-
}),
|
|
293
|
+
token: n.access_token,
|
|
294
|
+
expiresAt: Date.now() + n.expires_in * 1e3
|
|
295
|
+
}), n.access_token;
|
|
304
296
|
}
|
|
305
297
|
};
|
|
306
298
|
m.Scopes = {
|
|
@@ -308,49 +300,49 @@ m.Scopes = {
|
|
|
308
300
|
imap: "offline_access https://outlook.office.com/IMAP.AccessAsUser.All",
|
|
309
301
|
onedrive: "openid profile Files.ReadWrite.AppFolder offline_access"
|
|
310
302
|
};
|
|
311
|
-
let
|
|
312
|
-
const
|
|
303
|
+
let f = m;
|
|
304
|
+
const E = {
|
|
313
305
|
dropbox: p,
|
|
314
|
-
google:
|
|
315
|
-
microsoft:
|
|
306
|
+
google: l,
|
|
307
|
+
microsoft: f
|
|
316
308
|
};
|
|
317
|
-
function
|
|
318
|
-
return new
|
|
309
|
+
function x(r, e) {
|
|
310
|
+
return new E[e.provider](r);
|
|
319
311
|
}
|
|
320
|
-
async function
|
|
321
|
-
let
|
|
312
|
+
async function I(r, e) {
|
|
313
|
+
let o;
|
|
322
314
|
try {
|
|
323
|
-
|
|
315
|
+
o = r.getAccessToken();
|
|
324
316
|
} catch (s) {
|
|
325
|
-
if (!(s instanceof
|
|
317
|
+
if (!(s instanceof i))
|
|
326
318
|
throw s;
|
|
327
319
|
switch (s.code) {
|
|
328
320
|
case d: {
|
|
329
321
|
if (!e) throw s;
|
|
330
|
-
const
|
|
331
|
-
|
|
322
|
+
const n = await r.buildAuthUrl(), t = await e(n);
|
|
323
|
+
o = await r.finishAuth(new URL(t));
|
|
332
324
|
break;
|
|
333
325
|
}
|
|
334
326
|
case R: {
|
|
335
|
-
|
|
327
|
+
o = await r.refreshToken();
|
|
336
328
|
break;
|
|
337
329
|
}
|
|
338
330
|
default:
|
|
339
331
|
throw s;
|
|
340
332
|
}
|
|
341
333
|
}
|
|
342
|
-
return
|
|
334
|
+
return o;
|
|
343
335
|
}
|
|
344
336
|
export {
|
|
345
337
|
p as DropboxAuthorizer,
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
338
|
+
l as GoogleAuthorizer,
|
|
339
|
+
f as MicrosoftAuthorizer,
|
|
340
|
+
a as OAUTH2_AUTH_ERROR,
|
|
349
341
|
R as OAUTH2_NEED_REFRESH,
|
|
350
342
|
d as OAUTH2_UNAUTHORIZED,
|
|
351
343
|
w as OAuth2Authorizer,
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
344
|
+
E as OAuth2Authorizers,
|
|
345
|
+
i as OAuth2Error,
|
|
346
|
+
I as ensureAccessToken,
|
|
347
|
+
x as getAuthorizer
|
|
356
348
|
};
|
package/dist/types.d.ts
CHANGED
|
@@ -6,9 +6,21 @@ export interface TokenData {
|
|
|
6
6
|
}
|
|
7
7
|
export interface IOAuth2Options {
|
|
8
8
|
clientId: string;
|
|
9
|
-
clientSecret
|
|
9
|
+
/** clientSecret may be absent for client-side apps. */
|
|
10
|
+
clientSecret?: string;
|
|
10
11
|
redirectUrl: string;
|
|
11
12
|
scope?: string;
|
|
13
|
+
provider?: {
|
|
14
|
+
microsoft?: {
|
|
15
|
+
/**
|
|
16
|
+
* Must match the account type of the application registered in https://portal.azure.com/.
|
|
17
|
+
* `common` for all accounts, `consumers` for personal accounts only.
|
|
18
|
+
*
|
|
19
|
+
* Default as `common`.
|
|
20
|
+
*/
|
|
21
|
+
accountType?: "common" | "consumers";
|
|
22
|
+
};
|
|
23
|
+
};
|
|
12
24
|
onSetAccessToken?: (value: TokenData | null) => void;
|
|
13
25
|
onSetRefreshToken?: (value: TokenData | null) => void;
|
|
14
26
|
}
|