react-native-nitro-auth 0.5.8 → 0.5.10
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/CHANGELOG.md +48 -0
- package/README.md +69 -50
- package/cpp/HybridAuth.cpp +135 -50
- package/cpp/HybridAuth.hpp +1 -0
- package/ios/AuthAdapter.swift +28 -9
- package/lib/commonjs/Auth.web.js +141 -73
- package/lib/commonjs/Auth.web.js.map +1 -1
- package/lib/commonjs/create-auth-service.js +71 -0
- package/lib/commonjs/create-auth-service.js.map +1 -0
- package/lib/commonjs/service.js +2 -79
- package/lib/commonjs/service.js.map +1 -1
- package/lib/commonjs/service.web.js +2 -79
- package/lib/commonjs/service.web.js.map +1 -1
- package/lib/commonjs/use-auth.js +6 -3
- package/lib/commonjs/use-auth.js.map +1 -1
- package/lib/module/Auth.web.js +141 -73
- package/lib/module/Auth.web.js.map +1 -1
- package/lib/module/create-auth-service.js +67 -0
- package/lib/module/create-auth-service.js.map +1 -0
- package/lib/module/service.js +2 -79
- package/lib/module/service.js.map +1 -1
- package/lib/module/service.web.js +2 -79
- package/lib/module/service.web.js.map +1 -1
- package/lib/module/use-auth.js +6 -3
- package/lib/module/use-auth.js.map +1 -1
- package/lib/typescript/commonjs/Auth.web.d.ts +4 -2
- package/lib/typescript/commonjs/Auth.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/create-auth-service.d.ts +5 -0
- package/lib/typescript/commonjs/create-auth-service.d.ts.map +1 -0
- package/lib/typescript/commonjs/service.d.ts.map +1 -1
- package/lib/typescript/commonjs/service.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/use-auth.d.ts.map +1 -1
- package/lib/typescript/module/Auth.web.d.ts +4 -2
- package/lib/typescript/module/Auth.web.d.ts.map +1 -1
- package/lib/typescript/module/create-auth-service.d.ts +5 -0
- package/lib/typescript/module/create-auth-service.d.ts.map +1 -0
- package/lib/typescript/module/service.d.ts.map +1 -1
- package/lib/typescript/module/service.web.d.ts.map +1 -1
- package/lib/typescript/module/use-auth.d.ts.map +1 -1
- package/package.json +7 -5
- package/react-native-nitro-auth.podspec +1 -0
- package/src/Auth.web.ts +261 -102
- package/src/create-auth-service.ts +97 -0
- package/src/service.ts +3 -101
- package/src/service.web.ts +3 -101
- package/src/use-auth.ts +7 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_authError","require","wrapAuthOperation","operation","e","AuthError","from","createAuthService","getAuth","name","currentUser","grantedScopes","scopes","Array","isArray","hasPlayServices","login","provider","options","requestScopes","revokeScopes","getAccessToken","refreshToken","logout","silentRestore","onAuthStateChanged","callback","auth","onTokensRefreshed","setLoggingEnabled","enabled","dispose","equals","other"],"sourceRoot":"../../src","sources":["create-auth-service.ts"],"mappings":"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","ignoreList":[]}
|
package/lib/commonjs/service.js
CHANGED
|
@@ -5,88 +5,11 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.AuthService = void 0;
|
|
7
7
|
var _reactNativeNitroModules = require("react-native-nitro-modules");
|
|
8
|
-
var
|
|
8
|
+
var _createAuthService = require("./create-auth-service.js");
|
|
9
9
|
let nitroAuth;
|
|
10
10
|
function getNitroAuth() {
|
|
11
11
|
nitroAuth ??= _reactNativeNitroModules.NitroModules.createHybridObject("Auth");
|
|
12
12
|
return nitroAuth;
|
|
13
13
|
}
|
|
14
|
-
const AuthService = exports.AuthService =
|
|
15
|
-
get name() {
|
|
16
|
-
return getNitroAuth().name;
|
|
17
|
-
},
|
|
18
|
-
get currentUser() {
|
|
19
|
-
return getNitroAuth().currentUser;
|
|
20
|
-
},
|
|
21
|
-
get grantedScopes() {
|
|
22
|
-
return getNitroAuth().grantedScopes;
|
|
23
|
-
},
|
|
24
|
-
get hasPlayServices() {
|
|
25
|
-
return getNitroAuth().hasPlayServices;
|
|
26
|
-
},
|
|
27
|
-
async login(provider, options) {
|
|
28
|
-
try {
|
|
29
|
-
await getNitroAuth().login(provider, options);
|
|
30
|
-
return;
|
|
31
|
-
} catch (e) {
|
|
32
|
-
throw _authError.AuthError.from(e);
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
|
-
async requestScopes(scopes) {
|
|
36
|
-
try {
|
|
37
|
-
await getNitroAuth().requestScopes(scopes);
|
|
38
|
-
return;
|
|
39
|
-
} catch (e) {
|
|
40
|
-
throw _authError.AuthError.from(e);
|
|
41
|
-
}
|
|
42
|
-
},
|
|
43
|
-
async revokeScopes(scopes) {
|
|
44
|
-
try {
|
|
45
|
-
await getNitroAuth().revokeScopes(scopes);
|
|
46
|
-
return;
|
|
47
|
-
} catch (e) {
|
|
48
|
-
throw _authError.AuthError.from(e);
|
|
49
|
-
}
|
|
50
|
-
},
|
|
51
|
-
async getAccessToken() {
|
|
52
|
-
try {
|
|
53
|
-
return await getNitroAuth().getAccessToken();
|
|
54
|
-
} catch (e) {
|
|
55
|
-
throw _authError.AuthError.from(e);
|
|
56
|
-
}
|
|
57
|
-
},
|
|
58
|
-
async refreshToken() {
|
|
59
|
-
try {
|
|
60
|
-
return await getNitroAuth().refreshToken();
|
|
61
|
-
} catch (e) {
|
|
62
|
-
throw _authError.AuthError.from(e);
|
|
63
|
-
}
|
|
64
|
-
},
|
|
65
|
-
logout() {
|
|
66
|
-
getNitroAuth().logout();
|
|
67
|
-
},
|
|
68
|
-
async silentRestore() {
|
|
69
|
-
try {
|
|
70
|
-
await getNitroAuth().silentRestore();
|
|
71
|
-
return;
|
|
72
|
-
} catch (e) {
|
|
73
|
-
throw _authError.AuthError.from(e);
|
|
74
|
-
}
|
|
75
|
-
},
|
|
76
|
-
onAuthStateChanged(callback) {
|
|
77
|
-
return getNitroAuth().onAuthStateChanged(callback);
|
|
78
|
-
},
|
|
79
|
-
onTokensRefreshed(callback) {
|
|
80
|
-
return getNitroAuth().onTokensRefreshed(callback);
|
|
81
|
-
},
|
|
82
|
-
setLoggingEnabled(enabled) {
|
|
83
|
-
getNitroAuth().setLoggingEnabled(enabled);
|
|
84
|
-
},
|
|
85
|
-
dispose() {
|
|
86
|
-
getNitroAuth().dispose();
|
|
87
|
-
},
|
|
88
|
-
equals(other) {
|
|
89
|
-
return getNitroAuth().equals(other);
|
|
90
|
-
}
|
|
91
|
-
};
|
|
14
|
+
const AuthService = exports.AuthService = (0, _createAuthService.createAuthService)(getNitroAuth);
|
|
92
15
|
//# sourceMappingURL=service.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_reactNativeNitroModules","require","
|
|
1
|
+
{"version":3,"names":["_reactNativeNitroModules","require","_createAuthService","nitroAuth","getNitroAuth","NitroModules","createHybridObject","AuthService","exports","createAuthService"],"sourceRoot":"../../src","sources":["service.ts"],"mappings":";;;;;;AAAA,IAAAA,wBAAA,GAAAC,OAAA;AAEA,IAAAC,kBAAA,GAAAD,OAAA;AAEA,IAAIE,SAA2B;AAE/B,SAASC,YAAYA,CAAA,EAAS;EAC5BD,SAAS,KAAKE,qCAAY,CAACC,kBAAkB,CAAO,MAAM,CAAC;EAC3D,OAAOH,SAAS;AAClB;AAEO,MAAMI,WAAiB,GAAAC,OAAA,CAAAD,WAAA,GAAG,IAAAE,oCAAiB,EAACL,YAAY,CAAC","ignoreList":[]}
|
|
@@ -5,83 +5,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.AuthService = void 0;
|
|
7
7
|
var _AuthWeb = require("./Auth.web.js");
|
|
8
|
-
var
|
|
9
|
-
const AuthService = exports.AuthService =
|
|
10
|
-
get name() {
|
|
11
|
-
return _AuthWeb.AuthModule.name;
|
|
12
|
-
},
|
|
13
|
-
get currentUser() {
|
|
14
|
-
return _AuthWeb.AuthModule.currentUser;
|
|
15
|
-
},
|
|
16
|
-
get grantedScopes() {
|
|
17
|
-
return _AuthWeb.AuthModule.grantedScopes;
|
|
18
|
-
},
|
|
19
|
-
get hasPlayServices() {
|
|
20
|
-
return _AuthWeb.AuthModule.hasPlayServices;
|
|
21
|
-
},
|
|
22
|
-
async login(provider, options) {
|
|
23
|
-
try {
|
|
24
|
-
await _AuthWeb.AuthModule.login(provider, options);
|
|
25
|
-
return;
|
|
26
|
-
} catch (e) {
|
|
27
|
-
throw _authError.AuthError.from(e);
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
async requestScopes(scopes) {
|
|
31
|
-
try {
|
|
32
|
-
await _AuthWeb.AuthModule.requestScopes(scopes);
|
|
33
|
-
return;
|
|
34
|
-
} catch (e) {
|
|
35
|
-
throw _authError.AuthError.from(e);
|
|
36
|
-
}
|
|
37
|
-
},
|
|
38
|
-
async revokeScopes(scopes) {
|
|
39
|
-
try {
|
|
40
|
-
await _AuthWeb.AuthModule.revokeScopes(scopes);
|
|
41
|
-
return;
|
|
42
|
-
} catch (e) {
|
|
43
|
-
throw _authError.AuthError.from(e);
|
|
44
|
-
}
|
|
45
|
-
},
|
|
46
|
-
async getAccessToken() {
|
|
47
|
-
try {
|
|
48
|
-
return await _AuthWeb.AuthModule.getAccessToken();
|
|
49
|
-
} catch (e) {
|
|
50
|
-
throw _authError.AuthError.from(e);
|
|
51
|
-
}
|
|
52
|
-
},
|
|
53
|
-
async refreshToken() {
|
|
54
|
-
try {
|
|
55
|
-
return await _AuthWeb.AuthModule.refreshToken();
|
|
56
|
-
} catch (e) {
|
|
57
|
-
throw _authError.AuthError.from(e);
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
logout() {
|
|
61
|
-
_AuthWeb.AuthModule.logout();
|
|
62
|
-
},
|
|
63
|
-
async silentRestore() {
|
|
64
|
-
try {
|
|
65
|
-
await _AuthWeb.AuthModule.silentRestore();
|
|
66
|
-
return;
|
|
67
|
-
} catch (e) {
|
|
68
|
-
throw _authError.AuthError.from(e);
|
|
69
|
-
}
|
|
70
|
-
},
|
|
71
|
-
onAuthStateChanged(callback) {
|
|
72
|
-
return _AuthWeb.AuthModule.onAuthStateChanged(callback);
|
|
73
|
-
},
|
|
74
|
-
onTokensRefreshed(callback) {
|
|
75
|
-
return _AuthWeb.AuthModule.onTokensRefreshed(callback);
|
|
76
|
-
},
|
|
77
|
-
setLoggingEnabled(enabled) {
|
|
78
|
-
_AuthWeb.AuthModule.setLoggingEnabled(enabled);
|
|
79
|
-
},
|
|
80
|
-
dispose() {
|
|
81
|
-
_AuthWeb.AuthModule.dispose();
|
|
82
|
-
},
|
|
83
|
-
equals(other) {
|
|
84
|
-
return _AuthWeb.AuthModule.equals(other);
|
|
85
|
-
}
|
|
86
|
-
};
|
|
8
|
+
var _createAuthService = require("./create-auth-service.js");
|
|
9
|
+
const AuthService = exports.AuthService = (0, _createAuthService.createAuthService)(() => _AuthWeb.AuthModule);
|
|
87
10
|
//# sourceMappingURL=service.web.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_AuthWeb","require","
|
|
1
|
+
{"version":3,"names":["_AuthWeb","require","_createAuthService","AuthService","exports","createAuthService","AuthModule"],"sourceRoot":"../../src","sources":["service.web.ts"],"mappings":";;;;;;AACA,IAAAA,QAAA,GAAAC,OAAA;AACA,IAAAC,kBAAA,GAAAD,OAAA;AAEO,MAAME,WAAiB,GAAAC,OAAA,CAAAD,WAAA,GAAG,IAAAE,oCAAiB,EAAC,MAAMC,mBAAU,CAAC","ignoreList":[]}
|
package/lib/commonjs/use-auth.js
CHANGED
|
@@ -8,6 +8,9 @@ var _react = require("react");
|
|
|
8
8
|
var _service = require("./service");
|
|
9
9
|
var _authError = require("./utils/auth-error.js");
|
|
10
10
|
const EMPTY_SCOPES = [];
|
|
11
|
+
function normalizeScopes(scopes) {
|
|
12
|
+
return Array.isArray(scopes) ? scopes : EMPTY_SCOPES;
|
|
13
|
+
}
|
|
11
14
|
const areScopesEqual = (left, right) => {
|
|
12
15
|
if (left === right) return true;
|
|
13
16
|
if (left.length !== right.length) return false;
|
|
@@ -30,13 +33,13 @@ const areScopesEqual = (left, right) => {
|
|
|
30
33
|
function useAuth() {
|
|
31
34
|
const [state, setState] = (0, _react.useState)({
|
|
32
35
|
user: _service.AuthService.currentUser,
|
|
33
|
-
scopes: _service.AuthService.grantedScopes,
|
|
36
|
+
scopes: normalizeScopes(_service.AuthService.grantedScopes),
|
|
34
37
|
loading: false,
|
|
35
38
|
error: undefined
|
|
36
39
|
});
|
|
37
40
|
const syncStateFromService = (0, _react.useCallback)((nextLoading, nextError) => {
|
|
38
41
|
const nextUser = _service.AuthService.currentUser;
|
|
39
|
-
const nextScopes = _service.AuthService.grantedScopes;
|
|
42
|
+
const nextScopes = normalizeScopes(_service.AuthService.grantedScopes);
|
|
40
43
|
setState(prev => {
|
|
41
44
|
if (prev.loading === nextLoading && prev.error === nextError && prev.user === nextUser && areScopesEqual(prev.scopes, nextScopes)) {
|
|
42
45
|
return prev;
|
|
@@ -162,7 +165,7 @@ function useAuth() {
|
|
|
162
165
|
}, [syncStateFromService]);
|
|
163
166
|
(0, _react.useEffect)(() => {
|
|
164
167
|
const unsubscribeAuth = _service.AuthService.onAuthStateChanged(currentUser => {
|
|
165
|
-
const nextScopes = _service.AuthService.grantedScopes;
|
|
168
|
+
const nextScopes = normalizeScopes(_service.AuthService.grantedScopes);
|
|
166
169
|
setState(prev => {
|
|
167
170
|
if (prev.user === currentUser && areScopesEqual(prev.scopes, nextScopes) && prev.loading === false) {
|
|
168
171
|
return prev;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_react","require","_service","_authError","EMPTY_SCOPES","areScopesEqual","left","right","length","matchesInOrder","i","remaining","Set","scope","delete","size","useAuth","state","setState","useState","user","AuthService","currentUser","
|
|
1
|
+
{"version":3,"names":["_react","require","_service","_authError","EMPTY_SCOPES","normalizeScopes","scopes","Array","isArray","areScopesEqual","left","right","length","matchesInOrder","i","remaining","Set","scope","delete","size","useAuth","state","setState","useState","user","AuthService","currentUser","grantedScopes","loading","error","undefined","syncStateFromService","useCallback","nextLoading","nextError","nextUser","nextScopes","prev","login","provider","options","e","AuthError","from","logout","requestScopes","newScopes","revokeScopes","scopesToRevoke","getAccessToken","refreshToken","tokens","silentRestore","useEffect","unsubscribeAuth","onAuthStateChanged","unsubscribeTokens","onTokensRefreshed","useMemo","hasPlayServices"],"sourceRoot":"../../src","sources":["use-auth.ts"],"mappings":"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","ignoreList":[]}
|
package/lib/module/Auth.web.js
CHANGED
|
@@ -12,6 +12,8 @@ const STORAGE_MODE_MEMORY = "memory";
|
|
|
12
12
|
const POPUP_POLL_INTERVAL_MS = 100;
|
|
13
13
|
const POPUP_TIMEOUT_MS = 120000;
|
|
14
14
|
const WEB_STORAGE_MODES = new Set([STORAGE_MODE_SESSION, STORAGE_MODE_LOCAL, STORAGE_MODE_MEMORY]);
|
|
15
|
+
const WEB_AUTH_ERROR_CODES = new Set(["cancelled", "timeout", "popup_blocked", "network_error", "configuration_error", "not_signed_in", "operation_in_progress", "unsupported_provider", "invalid_state", "invalid_nonce", "token_error", "no_id_token", "parse_error", "refresh_failed", "unknown"]);
|
|
16
|
+
const JWT_BASE64_URL_RE = /^[A-Za-z0-9_-]+$/;
|
|
15
17
|
const inMemoryWebStorage = new Map();
|
|
16
18
|
let _appleSdkLoadPromise;
|
|
17
19
|
class AuthWebError extends Error {
|
|
@@ -29,7 +31,14 @@ const getOptionalString = (source, key) => {
|
|
|
29
31
|
};
|
|
30
32
|
const getOptionalNumber = (source, key) => {
|
|
31
33
|
const candidate = source[key];
|
|
32
|
-
return typeof candidate === "number" ? candidate : undefined;
|
|
34
|
+
return typeof candidate === "number" && Number.isFinite(candidate) ? candidate : undefined;
|
|
35
|
+
};
|
|
36
|
+
const parseExpiresInSeconds = value => {
|
|
37
|
+
const candidate = typeof value === "number" ? value : typeof value === "string" && value.trim().length > 0 ? Number(value) : undefined;
|
|
38
|
+
if (typeof candidate !== "number" || !Number.isFinite(candidate) || candidate < 0) {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
return candidate;
|
|
33
42
|
};
|
|
34
43
|
const parseAuthUser = value => {
|
|
35
44
|
if (!isJsonObject(value) || !isAuthProvider(value.provider)) {
|
|
@@ -57,6 +66,7 @@ const parseScopes = value => {
|
|
|
57
66
|
}
|
|
58
67
|
return value.filter(scope => typeof scope === "string");
|
|
59
68
|
};
|
|
69
|
+
const isAuthErrorCode = value => WEB_AUTH_ERROR_CODES.has(value);
|
|
60
70
|
const parseAuthWebExtraConfig = value => {
|
|
61
71
|
if (!isJsonObject(value)) {
|
|
62
72
|
return {};
|
|
@@ -313,9 +323,25 @@ class AuthWeb {
|
|
|
313
323
|
};
|
|
314
324
|
}
|
|
315
325
|
notify() {
|
|
316
|
-
this._listeners
|
|
317
|
-
|
|
318
|
-
}
|
|
326
|
+
for (const listener of [...this._listeners]) {
|
|
327
|
+
listener(this._currentUser);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
notifyTokenListeners(tokens) {
|
|
331
|
+
for (const listener of [...this._tokenListeners]) {
|
|
332
|
+
listener(tokens);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
async runLoginOperation(operation) {
|
|
336
|
+
if (this._loginInFlight) {
|
|
337
|
+
throw new AuthWebError("operation_in_progress", "Another login is already in progress");
|
|
338
|
+
}
|
|
339
|
+
this._loginInFlight = true;
|
|
340
|
+
try {
|
|
341
|
+
await operation();
|
|
342
|
+
} finally {
|
|
343
|
+
this._loginInFlight = false;
|
|
344
|
+
}
|
|
319
345
|
}
|
|
320
346
|
async login(provider, options) {
|
|
321
347
|
const loginHint = options?.loginHint;
|
|
@@ -323,15 +349,23 @@ class AuthWeb {
|
|
|
323
349
|
scopes: options?.scopes
|
|
324
350
|
});
|
|
325
351
|
try {
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
352
|
+
await this.runLoginOperation(async () => {
|
|
353
|
+
if (provider === "google") {
|
|
354
|
+
const scopes = options?.scopes ?? DEFAULT_SCOPES;
|
|
355
|
+
await this.loginGoogle(scopes, loginHint);
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
if (provider === "microsoft") {
|
|
359
|
+
const scopes = options?.scopes ?? MS_DEFAULT_SCOPES;
|
|
360
|
+
await this.loginMicrosoft(scopes, loginHint, options?.tenant, options?.prompt);
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
if (provider === "apple") {
|
|
364
|
+
await this.loginApple();
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
throw new AuthWebError("unsupported_provider", `Unsupported auth provider: ${provider}`);
|
|
368
|
+
});
|
|
335
369
|
logger.log(`Login successful with ${provider}`);
|
|
336
370
|
} catch (e) {
|
|
337
371
|
const error = this.mapError(e);
|
|
@@ -350,11 +384,13 @@ class AuthWeb {
|
|
|
350
384
|
logger.log("Requesting additional scopes:", scopes);
|
|
351
385
|
const newScopes = [...new Set([...this._grantedScopes, ...scopes])];
|
|
352
386
|
try {
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
387
|
+
await this.runLoginOperation(async () => {
|
|
388
|
+
if (provider === "google") {
|
|
389
|
+
await this.loginGoogle(newScopes);
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
356
392
|
await this.loginMicrosoft(newScopes);
|
|
357
|
-
}
|
|
393
|
+
});
|
|
358
394
|
} catch (e) {
|
|
359
395
|
const error = this.mapError(e);
|
|
360
396
|
logger.error("Requesting scopes failed:", error.message);
|
|
@@ -426,16 +462,15 @@ class AuthWeb {
|
|
|
426
462
|
});
|
|
427
463
|
const json = await this.parseResponseObject(response);
|
|
428
464
|
if (!response.ok) {
|
|
429
|
-
throw new
|
|
465
|
+
throw new AuthWebError("refresh_failed", getOptionalString(json, "error_description") ?? getOptionalString(json, "error") ?? "Token refresh failed");
|
|
430
466
|
}
|
|
431
467
|
const idToken = getOptionalString(json, "id_token");
|
|
432
468
|
const accessToken = getOptionalString(json, "access_token");
|
|
433
469
|
const newRefreshToken = getOptionalString(json, "refresh_token");
|
|
434
|
-
const expiresInSeconds = getOptionalNumber(json, "expires_in");
|
|
435
470
|
if (newRefreshToken) {
|
|
436
471
|
this.saveRefreshToken(newRefreshToken);
|
|
437
472
|
}
|
|
438
|
-
const expirationTime =
|
|
473
|
+
const expirationTime = this.getExpirationTime(json["expires_in"]);
|
|
439
474
|
const effectiveIdToken = idToken ?? this._currentUser.idToken;
|
|
440
475
|
const claims = effectiveIdToken ? this.decodeMicrosoftJwt(effectiveIdToken) : {};
|
|
441
476
|
const user = {
|
|
@@ -453,9 +488,7 @@ class AuthWeb {
|
|
|
453
488
|
refreshToken: newRefreshToken ?? undefined,
|
|
454
489
|
expirationTime
|
|
455
490
|
};
|
|
456
|
-
this.
|
|
457
|
-
l(tokens);
|
|
458
|
-
});
|
|
491
|
+
this.notifyTokenListeners(tokens);
|
|
459
492
|
return tokens;
|
|
460
493
|
}
|
|
461
494
|
if (this._currentUser.provider !== "google") {
|
|
@@ -469,16 +502,19 @@ class AuthWeb {
|
|
|
469
502
|
refreshToken: this._currentUser.refreshToken,
|
|
470
503
|
expirationTime: this._currentUser.expirationTime
|
|
471
504
|
};
|
|
472
|
-
this.
|
|
473
|
-
l(tokens);
|
|
474
|
-
});
|
|
505
|
+
this.notifyTokenListeners(tokens);
|
|
475
506
|
return tokens;
|
|
476
507
|
}
|
|
477
508
|
mapError(error) {
|
|
509
|
+
if (error instanceof AuthWebError) {
|
|
510
|
+
return error;
|
|
511
|
+
}
|
|
478
512
|
const rawMessage = error instanceof Error ? error.message : String(error);
|
|
479
513
|
const msg = rawMessage.toLowerCase();
|
|
480
|
-
let mappedMsg =
|
|
481
|
-
if (
|
|
514
|
+
let mappedMsg = "unknown";
|
|
515
|
+
if (isAuthErrorCode(rawMessage)) {
|
|
516
|
+
mappedMsg = rawMessage;
|
|
517
|
+
} else if (msg.includes("cancel") || msg.includes("popup_closed")) {
|
|
482
518
|
mappedMsg = "cancelled";
|
|
483
519
|
} else if (msg.includes("access_denied")) {
|
|
484
520
|
mappedMsg = "cancelled";
|
|
@@ -486,6 +522,18 @@ class AuthWeb {
|
|
|
486
522
|
mappedMsg = "timeout";
|
|
487
523
|
} else if (msg.includes("popup blocked")) {
|
|
488
524
|
mappedMsg = "popup_blocked";
|
|
525
|
+
} else if (msg.includes("login is already in progress")) {
|
|
526
|
+
mappedMsg = "operation_in_progress";
|
|
527
|
+
} else if (msg.includes("state mismatch")) {
|
|
528
|
+
mappedMsg = "invalid_state";
|
|
529
|
+
} else if (msg.includes("nonce mismatch")) {
|
|
530
|
+
mappedMsg = "invalid_nonce";
|
|
531
|
+
} else if (msg.includes("no id_token") || msg.includes("no_id_token")) {
|
|
532
|
+
mappedMsg = "no_id_token";
|
|
533
|
+
} else if (msg.includes("invalid jwt") || msg.includes("json")) {
|
|
534
|
+
mappedMsg = "parse_error";
|
|
535
|
+
} else if (msg.includes("no user logged in") || msg.includes("not signed in")) {
|
|
536
|
+
mappedMsg = "not_signed_in";
|
|
489
537
|
} else if (msg.includes("network") || msg.includes("server_error") || msg.includes("temporarily_unavailable")) {
|
|
490
538
|
mappedMsg = "network_error";
|
|
491
539
|
} else if (msg.includes("invalid_grant") || msg.includes("invalid_token")) {
|
|
@@ -496,24 +544,62 @@ class AuthWeb {
|
|
|
496
544
|
return new AuthWebError(mappedMsg, rawMessage);
|
|
497
545
|
}
|
|
498
546
|
async parseResponseObject(response) {
|
|
499
|
-
|
|
547
|
+
let parsed;
|
|
548
|
+
try {
|
|
549
|
+
parsed = await response.json();
|
|
550
|
+
} catch (error) {
|
|
551
|
+
throw new AuthWebError("parse_error", String(error));
|
|
552
|
+
}
|
|
500
553
|
if (!isJsonObject(parsed)) {
|
|
501
|
-
throw new
|
|
554
|
+
throw new AuthWebError("parse_error", "Expected JSON object response from auth provider");
|
|
502
555
|
}
|
|
503
556
|
return parsed;
|
|
504
557
|
}
|
|
505
558
|
parseJwtPayload(token) {
|
|
506
|
-
const
|
|
507
|
-
|
|
508
|
-
|
|
559
|
+
const parts = token.split(".");
|
|
560
|
+
const payload = parts[1];
|
|
561
|
+
if (parts.length < 2 || !payload || payload.length % 4 === 1 || !JWT_BASE64_URL_RE.test(payload)) {
|
|
562
|
+
throw new AuthWebError("parse_error", "Invalid JWT payload");
|
|
563
|
+
}
|
|
564
|
+
try {
|
|
565
|
+
const normalizedPayload = payload.replace(/-/g, "+").replace(/_/g, "/");
|
|
566
|
+
const padding = "=".repeat((4 - normalizedPayload.length % 4) % 4);
|
|
567
|
+
const binary = atob(`${normalizedPayload}${padding}`);
|
|
568
|
+
const decodedText = typeof TextDecoder === "function" ? new TextDecoder().decode(Uint8Array.from(binary, char => char.charCodeAt(0))) : decodeURIComponent(Array.from(binary, char => `%${char.charCodeAt(0).toString(16).padStart(2, "0")}`).join(""));
|
|
569
|
+
const decoded = JSON.parse(decodedText);
|
|
570
|
+
if (!isJsonObject(decoded)) {
|
|
571
|
+
throw new Error("Expected JWT payload to be an object");
|
|
572
|
+
}
|
|
573
|
+
return decoded;
|
|
574
|
+
} catch (error) {
|
|
575
|
+
if (error instanceof AuthWebError) {
|
|
576
|
+
throw error;
|
|
577
|
+
}
|
|
578
|
+
throw new AuthWebError("parse_error", String(error));
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
mapOAuthErrorCode(error) {
|
|
582
|
+
const normalizedError = error.trim().toLowerCase();
|
|
583
|
+
if (normalizedError === "access_denied" || normalizedError === "popup_closed_by_user" || normalizedError === "user_cancelled") {
|
|
584
|
+
return "cancelled";
|
|
509
585
|
}
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
const decoded = JSON.parse(atob(`${normalizedPayload}${padding}`));
|
|
513
|
-
if (!isJsonObject(decoded)) {
|
|
514
|
-
throw new Error("Expected JWT payload to be an object");
|
|
586
|
+
if (normalizedError === "server_error" || normalizedError === "temporarily_unavailable") {
|
|
587
|
+
return "network_error";
|
|
515
588
|
}
|
|
516
|
-
|
|
589
|
+
if (normalizedError === "invalid_client" || normalizedError === "invalid_scope" || normalizedError === "unauthorized_client") {
|
|
590
|
+
return "configuration_error";
|
|
591
|
+
}
|
|
592
|
+
if (normalizedError === "invalid_grant" || normalizedError === "invalid_token") {
|
|
593
|
+
return "token_error";
|
|
594
|
+
}
|
|
595
|
+
return "unknown";
|
|
596
|
+
}
|
|
597
|
+
getExpirationTime(expiresIn) {
|
|
598
|
+
const expiresInSeconds = parseExpiresInSeconds(expiresIn);
|
|
599
|
+
if (expiresInSeconds === undefined) {
|
|
600
|
+
return undefined;
|
|
601
|
+
}
|
|
602
|
+
return Date.now() + expiresInSeconds * 1000;
|
|
517
603
|
}
|
|
518
604
|
waitForPopupRedirect(popup, redirectUri, provider, onRedirect) {
|
|
519
605
|
return new Promise((resolve, reject) => {
|
|
@@ -551,7 +637,7 @@ class AuthWeb {
|
|
|
551
637
|
return;
|
|
552
638
|
}
|
|
553
639
|
cleanup(intervalId, timeoutId, true);
|
|
554
|
-
void Promise.resolve(onRedirect(url)).then(() => {
|
|
640
|
+
void Promise.resolve().then(() => onRedirect(url)).then(() => {
|
|
555
641
|
resolve();
|
|
556
642
|
}).catch(error => {
|
|
557
643
|
reject(error);
|
|
@@ -560,17 +646,6 @@ class AuthWeb {
|
|
|
560
646
|
});
|
|
561
647
|
}
|
|
562
648
|
async loginGoogle(scopes, loginHint) {
|
|
563
|
-
if (this._loginInFlight) {
|
|
564
|
-
throw new AuthWebError("cancelled", "Another login is already in progress");
|
|
565
|
-
}
|
|
566
|
-
this._loginInFlight = true;
|
|
567
|
-
try {
|
|
568
|
-
await this._loginGoogleInner(scopes, loginHint);
|
|
569
|
-
} finally {
|
|
570
|
-
this._loginInFlight = false;
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
async _loginGoogleInner(scopes, loginHint) {
|
|
574
649
|
const clientId = this._config.googleWebClientId;
|
|
575
650
|
if (!clientId) {
|
|
576
651
|
throw new Error("Google Web Client ID not configured. Add 'GOOGLE_WEB_CLIENT_ID' to your .env file.");
|
|
@@ -606,13 +681,18 @@ class AuthWeb {
|
|
|
606
681
|
const accessToken = params.get("access_token");
|
|
607
682
|
const expiresIn = params.get("expires_in");
|
|
608
683
|
const code = params.get("code");
|
|
684
|
+
const error = params.get("error");
|
|
685
|
+
const errorDescription = params.get("error_description");
|
|
686
|
+
if (error) {
|
|
687
|
+
throw new AuthWebError(this.mapOAuthErrorCode(error), errorDescription ?? error);
|
|
688
|
+
}
|
|
609
689
|
if (!idToken) {
|
|
610
|
-
throw new
|
|
690
|
+
throw new AuthWebError("no_id_token", "No id_token in response");
|
|
611
691
|
}
|
|
612
692
|
const decoded = this.parseJwtPayload(idToken);
|
|
613
693
|
if (decoded["nonce"] !== this._pendingGoogleNonce) {
|
|
614
694
|
this._pendingGoogleNonce = undefined;
|
|
615
|
-
throw new
|
|
695
|
+
throw new AuthWebError("invalid_nonce", "Nonce mismatch - possible replay attack");
|
|
616
696
|
}
|
|
617
697
|
this._pendingGoogleNonce = undefined;
|
|
618
698
|
this._grantedScopes = scopes;
|
|
@@ -623,7 +703,7 @@ class AuthWeb {
|
|
|
623
703
|
accessToken: accessToken ?? undefined,
|
|
624
704
|
serverAuthCode: code ?? undefined,
|
|
625
705
|
scopes,
|
|
626
|
-
expirationTime:
|
|
706
|
+
expirationTime: this.getExpirationTime(expiresIn),
|
|
627
707
|
...this.decodeGoogleJwt(idToken)
|
|
628
708
|
};
|
|
629
709
|
this.updateUser(user);
|
|
@@ -650,17 +730,6 @@ class AuthWeb {
|
|
|
650
730
|
}
|
|
651
731
|
}
|
|
652
732
|
async loginMicrosoft(scopes, loginHint, tenant, prompt) {
|
|
653
|
-
if (this._loginInFlight) {
|
|
654
|
-
throw new AuthWebError("cancelled", "Another login is already in progress");
|
|
655
|
-
}
|
|
656
|
-
this._loginInFlight = true;
|
|
657
|
-
try {
|
|
658
|
-
await this._loginMicrosoftInner(scopes, loginHint, tenant, prompt);
|
|
659
|
-
} finally {
|
|
660
|
-
this._loginInFlight = false;
|
|
661
|
-
}
|
|
662
|
-
}
|
|
663
|
-
async _loginMicrosoftInner(scopes, loginHint, tenant, prompt) {
|
|
664
733
|
const clientId = this._config.microsoftClientId;
|
|
665
734
|
if (!clientId) {
|
|
666
735
|
throw new Error("Microsoft Client ID not configured. Add 'microsoftClientId' to expo.extra in your app.config.js");
|
|
@@ -705,13 +774,13 @@ class AuthWeb {
|
|
|
705
774
|
const error = urlObj.searchParams.get("error");
|
|
706
775
|
const errorDescription = urlObj.searchParams.get("error_description");
|
|
707
776
|
if (error) {
|
|
708
|
-
throw new
|
|
777
|
+
throw new AuthWebError(this.mapOAuthErrorCode(error), errorDescription ?? error);
|
|
709
778
|
}
|
|
710
779
|
if (returnedState !== state) {
|
|
711
|
-
throw new
|
|
780
|
+
throw new AuthWebError("invalid_state", "State mismatch - possible CSRF attack");
|
|
712
781
|
}
|
|
713
782
|
if (!code) {
|
|
714
|
-
throw new
|
|
783
|
+
throw new AuthWebError("token_error", "No authorization code in response");
|
|
715
784
|
}
|
|
716
785
|
await this.exchangeMicrosoftCodeForTokens(code, codeVerifier, clientId, redirectUri, effectiveTenant, nonce, effectiveScopes);
|
|
717
786
|
}).then(() => {
|
|
@@ -755,20 +824,19 @@ class AuthWeb {
|
|
|
755
824
|
});
|
|
756
825
|
const json = await this.parseResponseObject(response);
|
|
757
826
|
if (!response.ok) {
|
|
758
|
-
throw new
|
|
827
|
+
throw new AuthWebError("token_error", getOptionalString(json, "error_description") ?? getOptionalString(json, "error") ?? "Token exchange failed");
|
|
759
828
|
}
|
|
760
829
|
const idToken = getOptionalString(json, "id_token");
|
|
761
830
|
if (!idToken) {
|
|
762
|
-
throw new
|
|
831
|
+
throw new AuthWebError("no_id_token", "No id_token in token response");
|
|
763
832
|
}
|
|
764
833
|
const claims = this.decodeMicrosoftJwt(idToken);
|
|
765
834
|
const payload = this.parseJwtPayload(idToken);
|
|
766
835
|
if (getOptionalString(payload, "nonce") !== expectedNonce) {
|
|
767
|
-
throw new
|
|
836
|
+
throw new AuthWebError("invalid_nonce", "Nonce mismatch - token may be replayed");
|
|
768
837
|
}
|
|
769
838
|
const accessToken = getOptionalString(json, "access_token");
|
|
770
839
|
const refreshToken = getOptionalString(json, "refresh_token");
|
|
771
|
-
const expiresInSeconds = getOptionalNumber(json, "expires_in");
|
|
772
840
|
if (refreshToken) {
|
|
773
841
|
this.saveRefreshToken(refreshToken);
|
|
774
842
|
}
|
|
@@ -780,7 +848,7 @@ class AuthWeb {
|
|
|
780
848
|
accessToken: accessToken ?? undefined,
|
|
781
849
|
refreshToken: refreshToken ?? undefined,
|
|
782
850
|
scopes,
|
|
783
|
-
expirationTime:
|
|
851
|
+
expirationTime: this.getExpirationTime(json["expires_in"]),
|
|
784
852
|
...claims
|
|
785
853
|
};
|
|
786
854
|
this.updateUser(user);
|