capacitor-oidc 0.0.6 → 0.1.1

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.
Files changed (37) hide show
  1. package/README.md +32 -25
  2. package/SECURITY.md +27 -30
  3. package/dist/esm/base-capacitor-user-manager.d.ts +30 -0
  4. package/dist/esm/base-capacitor-user-manager.js +104 -0
  5. package/dist/esm/base-capacitor-user-manager.js.map +1 -0
  6. package/dist/esm/capacitor-user-manager.d.ts +9 -32
  7. package/dist/esm/capacitor-user-manager.js +20 -174
  8. package/dist/esm/capacitor-user-manager.js.map +1 -1
  9. package/dist/esm/configuration.d.ts +14 -0
  10. package/dist/esm/configuration.js +72 -0
  11. package/dist/esm/configuration.js.map +1 -0
  12. package/dist/esm/definitions.d.ts +53 -3
  13. package/dist/esm/definitions.js.map +1 -1
  14. package/dist/esm/index.d.ts +5 -4
  15. package/dist/esm/index.js +8 -2
  16. package/dist/esm/index.js.map +1 -1
  17. package/dist/esm/native-capacitor-user-manager.d.ts +24 -0
  18. package/dist/esm/native-capacitor-user-manager.js +112 -0
  19. package/dist/esm/native-capacitor-user-manager.js.map +1 -0
  20. package/dist/esm/web-capacitor-user-manager.d.ts +11 -0
  21. package/dist/esm/web-capacitor-user-manager.js +44 -0
  22. package/dist/esm/web-capacitor-user-manager.js.map +1 -0
  23. package/dist/plugin.cjs +303 -126
  24. package/dist/plugin.cjs.map +1 -1
  25. package/docs/API.md +106 -60
  26. package/docs/GETTING_STARTED.md +85 -62
  27. package/docs/PLATFORM_SETUP.md +15 -4
  28. package/docs/PROVIDERS.md +52 -45
  29. package/docs/README.md +4 -4
  30. package/docs/TESTING.md +3 -1
  31. package/docs/TROUBLESHOOTING.md +23 -13
  32. package/docs/adr/0004-use-one-manager-across-platforms.md +64 -0
  33. package/docs/adr/index.md +6 -0
  34. package/docs/frameworks/ANGULAR.md +129 -0
  35. package/docs/frameworks/REACT.md +134 -0
  36. package/docs/frameworks/VUE.md +118 -0
  37. package/package.json +8 -2
package/README.md CHANGED
@@ -4,16 +4,17 @@
4
4
  [![CI](https://github.com/jojopirker/capacitor-oidc/actions/workflows/ci.yml/badge.svg)](https://github.com/jojopirker/capacitor-oidc/actions/workflows/ci.yml)
5
5
  [![license](https://img.shields.io/npm/l/capacitor-oidc)](LICENSE)
6
6
 
7
- `capacitor-oidc` is a simple OAuth 2.0 and OpenID Connect implementation for
8
- Capacitor 7 and 8 on native iOS and Android, powered by
7
+ `capacitor-oidc` is one OAuth 2.0 and OpenID Connect client for Capacitor web,
8
+ iOS, and Android applications, powered by
9
9
  [`oidc-client-ts`](https://github.com/authts/oidc-client-ts). It uses
10
- Authorization Code Flow with PKCE, native system authentication UI, and secure
11
- storage.
10
+ Authorization Code Flow with PKCE, native system authentication UI and secure
11
+ storage on mobile, and standard browser navigation and storage on web.
12
12
 
13
13
  ## Why `capacitor-oidc`?
14
14
 
15
15
  - Simple standards-based OAuth 2.0 and OIDC for Capacitor, without
16
16
  provider-specific SDKs.
17
+ - One manager and configuration contract across web, iOS, and Android.
17
18
  - The familiar `oidc-client-ts` `UserManager` API, session objects, and events.
18
19
  - System authentication UI instead of an embedded WebView.
19
20
  - Secure native storage for OIDC transactions and sessions.
@@ -32,7 +33,7 @@ AndroidX Auth Tab with its Custom Tab fallback.
32
33
  | Android | API 24 or newer; Auth Tab or Custom Tab |
33
34
  | Flow | Authorization Code Flow with PKCE |
34
35
  | Providers | Compatible OAuth 2.0 and OpenID Connect APIs |
35
- | Web | Use `oidc-client-ts` directly |
36
+ | Web | Redirect or popup navigation |
36
37
 
37
38
  ## Demo
38
39
 
@@ -49,8 +50,8 @@ the provider.
49
50
  - Android API 24 or newer
50
51
  - Android compile SDK 36, Java 21, and a compatible Android Gradle Plugin
51
52
  - an OAuth public client using Authorization Code Flow with PKCE
52
- - Web Crypto in the packaged Capacitor WebView
53
- - CORS support for the app's Capacitor origin on OIDC HTTP endpoints
53
+ - Web Crypto in every target runtime
54
+ - CORS support for web application and Capacitor origins on OIDC HTTP endpoints
54
55
 
55
56
  Never ship a client secret in a Capacitor application.
56
57
 
@@ -66,38 +67,44 @@ npx cap sync
66
67
  ```ts
67
68
  import { CapacitorUserManager } from 'capacitor-oidc';
68
69
 
69
- const manager = await CapacitorUserManager.create(
70
- {
70
+ const manager = await CapacitorUserManager.create({
71
+ common: {
71
72
  authority: 'https://identity.example.com',
72
- client_id: 'mobile-app',
73
- redirect_uri: 'com.example.app:/callback',
74
- post_logout_redirect_uri: 'com.example.app:/logout-callback',
73
+ client_id: 'public-app',
75
74
  scope: 'openid profile offline_access',
76
75
  automaticSilentRenew: true,
77
76
  revokeTokensOnSignout: true,
78
77
  },
79
- {
80
- storageNamespace: 'primary',
78
+ web: {
79
+ settings: {
80
+ redirect_uri: `${window.location.origin}/callback`,
81
+ post_logout_redirect_uri: `${window.location.origin}/logout-callback`,
82
+ },
81
83
  },
82
- );
84
+ native: {
85
+ settings: {
86
+ redirect_uri: 'com.example.app:/callback',
87
+ post_logout_redirect_uri: 'com.example.app:/logout-callback',
88
+ },
89
+ options: { storageNamespace: 'primary' },
90
+ },
91
+ });
83
92
 
84
- const user = await manager.signin();
93
+ await manager.signin();
85
94
  const validUser = await manager.getValidUser(30);
86
95
 
87
96
  await manager.signout();
88
97
  await manager.dispose();
89
98
  ```
90
99
 
91
- Register the redirect and post-logout redirect URIs exactly at your provider and
92
- in the native application. The provider client must be public and must allow
93
- Authorization Code Flow with PKCE.
94
-
95
- `CapacitorUserManager` is for native Capacitor runtimes. For a browser build, use
96
- the normal `UserManager` from `oidc-client-ts` and select the implementation with
97
- `Capacitor.isNativePlatform()` in the application.
100
+ Register every configured redirect and post-logout redirect URI exactly at your
101
+ provider, and register the native schemes in each native application. On the web
102
+ callback route, call `signinCallback()`; on the web logout callback route, call
103
+ `signoutCallback()`. The package detects the runtime and applies `common`, then
104
+ `web` or `native`, then the matching `ios` or `android` override.
98
105
 
99
106
  A runnable Keycloak-backed iOS application and its UI test live in
100
- [`example`](example).
107
+ [`example`](example/).
101
108
 
102
109
  ## Documentation
103
110
 
@@ -120,7 +127,7 @@ npm run verify:android
120
127
 
121
128
  Architecture decisions and contributor constraints are documented in
122
129
  [ARCHITECTURE.md](ARCHITECTURE.md), [REQUIREMENTS.md](REQUIREMENTS.md), and
123
- [docs/adr](docs/adr).
130
+ [docs/adr](docs/adr/).
124
131
 
125
132
  ## License
126
133
 
package/SECURITY.md CHANGED
@@ -7,36 +7,10 @@
7
7
  and storing state securely. The package does not patch `fetch`, process JWTs, or
8
8
  implement OAuth endpoints in Swift or Java.
9
9
 
10
- Installed applications are public clients. They must use Authorization Code Flow
11
- with PKCE and must not contain a client secret. Authorization and provider logout
12
- run in system authentication UI, never an embedded WebView.
13
-
14
- ## ID-token validation in `oidc-client-ts` 3.5.0
15
-
16
- The pinned `oidc-client-ts` 3.5.0 decodes ID-token claims and validates `sub`,
17
- `nonce`, and selected refresh-token continuity claims. It does not independently
18
- compare the decoded `iss`, `aud`, and `exp` claims with the configured client and
19
- current time. This behavior is visible in the
20
- [v3.5.0 ResponseValidator](https://github.com/authts/oidc-client-ts/blob/v3.5.0/src/ResponseValidator.ts)
21
- and is the subject of the open upstream report
22
- [authts/oidc-client-ts#2475](https://github.com/authts/oidc-client-ts/issues/2475).
23
-
24
- The practical exposure is narrower than an implicit-flow token parser: this
25
- package uses Authorization Code Flow only, and the token response comes from the
26
- configured token endpoint over TLS after state, nonce, and PKCE processing. The
27
- upstream project has not yet classified or resolved the report.
28
-
29
- This is a standards-conformance and threat-model consideration, not a categorical
30
- claim that every application using `oidc-client-ts` is unsafe. Consumers should
31
- evaluate it against their provider, reliance on ID-token claims, and assurance
32
- requirements. Resource servers must always validate access tokens independently;
33
- an application must not use unverified client-side profile claims as its API
34
- authorization boundary.
35
-
36
- The package will follow the upstream resolution and cover the expected behavior
37
- in provider integration tests before a stable v1 decision. It will not add a
38
- package-local JWT or cryptographic-validation layer, because duplicating protocol
39
- security code would expand the attack surface and create a second OIDC engine.
10
+ All configured applications are public clients. They use Authorization Code Flow
11
+ with PKCE and cannot contain a client secret. Native authorization and provider
12
+ logout run in system authentication UI, never an embedded WebView; web uses
13
+ normal browser redirect or popup navigation.
40
14
 
41
15
  ## Secure-storage boundary
42
16
 
@@ -58,3 +32,26 @@ absent. Their behavior must be verified in packaged applications on supported
58
32
  physical devices.
59
33
 
60
34
  See [Testing](docs/TESTING.md) for current platform and provider coverage.
35
+
36
+ ## Known issues
37
+
38
+ ### ID-token claim validation in `oidc-client-ts` 3.5.0
39
+
40
+ The pinned `oidc-client-ts` 3.5.0 decodes ID-token claims and validates `sub`,
41
+ `nonce`, and selected refresh-token continuity claims. It does not independently
42
+ compare the decoded `iss`, `aud`, and `exp` claims with the configured client and
43
+ current time. This behavior is visible in the
44
+ [v3.5.0 ResponseValidator](https://github.com/authts/oidc-client-ts/blob/v3.5.0/src/ResponseValidator.ts)
45
+ and is the subject of the unresolved upstream report
46
+ [authts/oidc-client-ts#2475](https://github.com/authts/oidc-client-ts/issues/2475).
47
+
48
+ This package uses Authorization Code Flow, so the token response comes from the
49
+ configured token endpoint over TLS after state, nonce, and PKCE processing.
50
+ Applications that rely on `iss`, `aud`, or `exp` claims should still evaluate
51
+ the upstream gap against their assurance requirements. Resource servers must
52
+ validate access tokens independently, and client-side ID-token claims must not
53
+ be an API authorization boundary.
54
+
55
+ The package will follow the upstream resolution and cover the expected behavior
56
+ in provider integration tests before a stable v1 decision. It will not add a
57
+ package-local JWT validation layer that would duplicate protocol security code.
@@ -0,0 +1,30 @@
1
+ import { UserManager, type INavigator, type SigninRedirectArgs, type SigninResourceOwnerCredentialsArgs, type SigninSilentArgs, type SignoutRedirectArgs, type User } from 'oidc-client-ts';
2
+ import type { ResolvedUserManagerConfiguration } from './configuration.js';
3
+ import type { CapacitorSigninArgs, CapacitorSignoutArgs } from './definitions.js';
4
+ export declare abstract class BaseCapacitorUserManager extends UserManager {
5
+ private automaticRenewalPromise?;
6
+ private refreshPromise?;
7
+ private readonly signinMode;
8
+ private readonly signoutMode;
9
+ private readonly defaultSigninArgs;
10
+ private readonly defaultSignoutArgs;
11
+ protected constructor(configuration: ResolvedUserManagerConfiguration, redirectNavigator?: INavigator, popupNavigator?: INavigator, iframeNavigator?: INavigator);
12
+ protected initialize(): Promise<void>;
13
+ signin(args?: CapacitorSigninArgs): Promise<void>;
14
+ signout(args?: CapacitorSignoutArgs): Promise<void>;
15
+ getValidUser(minimumValiditySeconds?: number): Promise<User | null>;
16
+ signinPopup(args?: CapacitorSigninArgs): Promise<User>;
17
+ signoutPopup(args?: CapacitorSignoutArgs): Promise<void>;
18
+ signinRedirect(args?: SigninRedirectArgs): Promise<void>;
19
+ signoutRedirect(args?: SignoutRedirectArgs): Promise<void>;
20
+ signinSilent(args?: SigninSilentArgs): Promise<User | null>;
21
+ signinResourceOwnerCredentials(_args: SigninResourceOwnerCredentialsArgs): Promise<User>;
22
+ removeUser(): Promise<void>;
23
+ cancel(): Promise<void>;
24
+ dispose(): Promise<void>;
25
+ protected performSilentSignin(args: SigninSilentArgs): Promise<User | null>;
26
+ protected removeUserWithoutWaiting(): Promise<void>;
27
+ protected checkForAutomaticRenewal(): void;
28
+ protected abstract disposePlatform(): Promise<void>;
29
+ private waitForRenewal;
30
+ }
@@ -0,0 +1,104 @@
1
+ import { UserManager, } from 'oidc-client-ts';
2
+ import { unsupported } from './errors.js';
3
+ export class BaseCapacitorUserManager extends UserManager {
4
+ automaticRenewalPromise;
5
+ refreshPromise;
6
+ signinMode;
7
+ signoutMode;
8
+ defaultSigninArgs;
9
+ defaultSignoutArgs;
10
+ constructor(configuration, redirectNavigator, popupNavigator, iframeNavigator) {
11
+ super(configuration.settings, redirectNavigator, popupNavigator, iframeNavigator);
12
+ this.signinMode = configuration.signinMode;
13
+ this.signoutMode = configuration.signoutMode;
14
+ this.defaultSigninArgs = configuration.signinArgs;
15
+ this.defaultSignoutArgs = configuration.signoutArgs;
16
+ }
17
+ async initialize() {
18
+ await this.getUser();
19
+ }
20
+ async signin(args = {}) {
21
+ const mergedArgs = { ...this.defaultSigninArgs, ...args };
22
+ if (this.signinMode === 'redirect')
23
+ return this.signinRedirect(mergedArgs);
24
+ await this.signinPopup(mergedArgs);
25
+ }
26
+ async signout(args = {}) {
27
+ const mergedArgs = { ...this.defaultSignoutArgs, ...args };
28
+ if (this.signoutMode === 'redirect')
29
+ return this.signoutRedirect(mergedArgs);
30
+ await this.signoutPopup(mergedArgs);
31
+ }
32
+ async getValidUser(minimumValiditySeconds = 60) {
33
+ const user = await this.getUser();
34
+ if (!user)
35
+ return null;
36
+ if (user.expires_in === undefined || user.expires_in > minimumValiditySeconds)
37
+ return user;
38
+ return this.signinSilent();
39
+ }
40
+ async signinPopup(args = {}) {
41
+ await this.waitForRenewal();
42
+ return super.signinPopup(args);
43
+ }
44
+ async signoutPopup(args = {}) {
45
+ await this.waitForRenewal();
46
+ await super.signoutPopup(args);
47
+ }
48
+ async signinRedirect(args = {}) {
49
+ await this.waitForRenewal();
50
+ await super.signinRedirect(args);
51
+ }
52
+ async signoutRedirect(args = {}) {
53
+ await this.waitForRenewal();
54
+ await super.signoutRedirect(args);
55
+ }
56
+ signinSilent(args = {}) {
57
+ if (!this.refreshPromise) {
58
+ const refresh = this.performSilentSignin(args);
59
+ this.refreshPromise = refresh.finally(() => {
60
+ this.refreshPromise = undefined;
61
+ });
62
+ }
63
+ return this.refreshPromise;
64
+ }
65
+ async signinResourceOwnerCredentials(_args) {
66
+ unsupported('Resource Owner Password Credentials');
67
+ }
68
+ async removeUser() {
69
+ await this.waitForRenewal();
70
+ await this.removeUserWithoutWaiting();
71
+ }
72
+ cancel() {
73
+ return Promise.resolve();
74
+ }
75
+ async dispose() {
76
+ this.stopSilentRenew();
77
+ await this.disposePlatform();
78
+ await this.waitForRenewal();
79
+ await this.cancel();
80
+ }
81
+ performSilentSignin(args) {
82
+ return super.signinSilent(args);
83
+ }
84
+ removeUserWithoutWaiting() {
85
+ return super.removeUser();
86
+ }
87
+ checkForAutomaticRenewal() {
88
+ if (!this.settings.automaticSilentRenew || this.automaticRenewalPromise)
89
+ return;
90
+ const renewal = this.getValidUser();
91
+ this.automaticRenewalPromise = renewal;
92
+ void renewal
93
+ .catch((error) => this.events._raiseSilentRenewError(error instanceof Error ? error : new Error('Silent renewal failed')))
94
+ .finally(() => {
95
+ if (this.automaticRenewalPromise === renewal)
96
+ this.automaticRenewalPromise = undefined;
97
+ });
98
+ }
99
+ async waitForRenewal() {
100
+ await this.automaticRenewalPromise?.catch(() => undefined);
101
+ await this.refreshPromise?.catch(() => undefined);
102
+ }
103
+ }
104
+ //# sourceMappingURL=base-capacitor-user-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-capacitor-user-manager.js","sourceRoot":"","sources":["../../src/base-capacitor-user-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,GAOZ,MAAM,gBAAgB,CAAC;AAIxB,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,OAAgB,wBAAyB,SAAQ,WAAW;IACxD,uBAAuB,CAAwB;IAC/C,cAAc,CAAwB;IAC7B,UAAU,CAAuB;IACjC,WAAW,CAAuB;IAClC,iBAAiB,CAAsB;IACvC,kBAAkB,CAAuB;IAE1D,YACE,aAA+C,EAC/C,iBAA8B,EAC9B,cAA2B,EAC3B,eAA4B;QAE5B,KAAK,CAAC,aAAa,CAAC,QAAQ,EAAE,iBAAiB,EAAE,cAAc,EAAE,eAAe,CAAC,CAAC;QAClF,IAAI,CAAC,UAAU,GAAG,aAAa,CAAC,UAAU,CAAC;QAC3C,IAAI,CAAC,WAAW,GAAG,aAAa,CAAC,WAAW,CAAC;QAC7C,IAAI,CAAC,iBAAiB,GAAG,aAAa,CAAC,UAAU,CAAC;QAClD,IAAI,CAAC,kBAAkB,GAAG,aAAa,CAAC,WAAW,CAAC;IACtD,CAAC;IAES,KAAK,CAAC,UAAU;QACxB,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,OAA4B,EAAE;QACzC,MAAM,UAAU,GAAG,EAAE,GAAG,IAAI,CAAC,iBAAiB,EAAE,GAAG,IAAI,EAAE,CAAC;QAC1D,IAAI,IAAI,CAAC,UAAU,KAAK,UAAU;YAAE,OAAO,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;QAC3E,MAAM,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;IACrC,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,OAA6B,EAAE;QAC3C,MAAM,UAAU,GAAG,EAAE,GAAG,IAAI,CAAC,kBAAkB,EAAE,GAAG,IAAI,EAAE,CAAC;QAC3D,IAAI,IAAI,CAAC,WAAW,KAAK,UAAU;YAAE,OAAO,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC;QAC7E,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;IACtC,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,sBAAsB,GAAG,EAAE;QAC5C,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QAClC,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAC;QACvB,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,IAAI,IAAI,CAAC,UAAU,GAAG,sBAAsB;YAAE,OAAO,IAAI,CAAC;QAC3F,OAAO,IAAI,CAAC,YAAY,EAAE,CAAC;IAC7B,CAAC;IAEQ,KAAK,CAAC,WAAW,CAAC,OAA4B,EAAE;QACvD,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC;QAC5B,OAAO,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC;IAEQ,KAAK,CAAC,YAAY,CAAC,OAA6B,EAAE;QACzD,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC;QAC5B,MAAM,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC;IAEQ,KAAK,CAAC,cAAc,CAAC,OAA2B,EAAE;QACzD,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC;QAC5B,MAAM,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;IAEQ,KAAK,CAAC,eAAe,CAAC,OAA4B,EAAE;QAC3D,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC;QAC5B,MAAM,KAAK,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;IAEQ,YAAY,CAAC,OAAyB,EAAE;QAC/C,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;YACzB,MAAM,OAAO,GAAG,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC;YAC/C,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE;gBACzC,IAAI,CAAC,cAAc,GAAG,SAAS,CAAC;YAClC,CAAC,CAAC,CAAC;QACL,CAAC;QACD,OAAO,IAAI,CAAC,cAAc,CAAC;IAC7B,CAAC;IAEQ,KAAK,CAAC,8BAA8B,CAAC,KAAyC;QACrF,WAAW,CAAC,qCAAqC,CAAC,CAAC;IACrD,CAAC;IAEQ,KAAK,CAAC,UAAU;QACvB,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC;QAC5B,MAAM,IAAI,CAAC,wBAAwB,EAAE,CAAC;IACxC,CAAC;IAED,MAAM;QACJ,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;IAED,KAAK,CAAC,OAAO;QACX,IAAI,CAAC,eAAe,EAAE,CAAC;QACvB,MAAM,IAAI,CAAC,eAAe,EAAE,CAAC;QAC7B,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC;QAC5B,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;IACtB,CAAC;IAES,mBAAmB,CAAC,IAAsB;QAClD,OAAO,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC;IAES,wBAAwB;QAChC,OAAO,KAAK,CAAC,UAAU,EAAE,CAAC;IAC5B,CAAC;IAES,wBAAwB;QAChC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,oBAAoB,IAAI,IAAI,CAAC,uBAAuB;YAAE,OAAO;QAChF,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;QACpC,IAAI,CAAC,uBAAuB,GAAG,OAAO,CAAC;QACvC,KAAK,OAAO;aACT,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE,CACxB,IAAI,CAAC,MAAM,CAAC,sBAAsB,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC,CACxG;aACA,OAAO,CAAC,GAAG,EAAE;YACZ,IAAI,IAAI,CAAC,uBAAuB,KAAK,OAAO;gBAAE,IAAI,CAAC,uBAAuB,GAAG,SAAS,CAAC;QACzF,CAAC,CAAC,CAAC;IACP,CAAC;IAIO,KAAK,CAAC,cAAc;QAC1B,MAAM,IAAI,CAAC,uBAAuB,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC3D,MAAM,IAAI,CAAC,cAAc,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC;CACF","sourcesContent":["import {\n UserManager,\n type INavigator,\n type SigninRedirectArgs,\n type SigninResourceOwnerCredentialsArgs,\n type SigninSilentArgs,\n type SignoutRedirectArgs,\n type User,\n} from 'oidc-client-ts';\n\nimport type { ResolvedUserManagerConfiguration } from './configuration.js';\nimport type { CapacitorSigninArgs, CapacitorSignoutArgs } from './definitions.js';\nimport { unsupported } from './errors.js';\n\nexport abstract class BaseCapacitorUserManager extends UserManager {\n private automaticRenewalPromise?: Promise<User | null>;\n private refreshPromise?: Promise<User | null>;\n private readonly signinMode: 'popup' | 'redirect';\n private readonly signoutMode: 'popup' | 'redirect';\n private readonly defaultSigninArgs: CapacitorSigninArgs;\n private readonly defaultSignoutArgs: CapacitorSignoutArgs;\n\n protected constructor(\n configuration: ResolvedUserManagerConfiguration,\n redirectNavigator?: INavigator,\n popupNavigator?: INavigator,\n iframeNavigator?: INavigator,\n ) {\n super(configuration.settings, redirectNavigator, popupNavigator, iframeNavigator);\n this.signinMode = configuration.signinMode;\n this.signoutMode = configuration.signoutMode;\n this.defaultSigninArgs = configuration.signinArgs;\n this.defaultSignoutArgs = configuration.signoutArgs;\n }\n\n protected async initialize(): Promise<void> {\n await this.getUser();\n }\n\n async signin(args: CapacitorSigninArgs = {}): Promise<void> {\n const mergedArgs = { ...this.defaultSigninArgs, ...args };\n if (this.signinMode === 'redirect') return this.signinRedirect(mergedArgs);\n await this.signinPopup(mergedArgs);\n }\n\n async signout(args: CapacitorSignoutArgs = {}): Promise<void> {\n const mergedArgs = { ...this.defaultSignoutArgs, ...args };\n if (this.signoutMode === 'redirect') return this.signoutRedirect(mergedArgs);\n await this.signoutPopup(mergedArgs);\n }\n\n async getValidUser(minimumValiditySeconds = 60): Promise<User | null> {\n const user = await this.getUser();\n if (!user) return null;\n if (user.expires_in === undefined || user.expires_in > minimumValiditySeconds) return user;\n return this.signinSilent();\n }\n\n override async signinPopup(args: CapacitorSigninArgs = {}): Promise<User> {\n await this.waitForRenewal();\n return super.signinPopup(args);\n }\n\n override async signoutPopup(args: CapacitorSignoutArgs = {}): Promise<void> {\n await this.waitForRenewal();\n await super.signoutPopup(args);\n }\n\n override async signinRedirect(args: SigninRedirectArgs = {}): Promise<void> {\n await this.waitForRenewal();\n await super.signinRedirect(args);\n }\n\n override async signoutRedirect(args: SignoutRedirectArgs = {}): Promise<void> {\n await this.waitForRenewal();\n await super.signoutRedirect(args);\n }\n\n override signinSilent(args: SigninSilentArgs = {}): Promise<User | null> {\n if (!this.refreshPromise) {\n const refresh = this.performSilentSignin(args);\n this.refreshPromise = refresh.finally(() => {\n this.refreshPromise = undefined;\n });\n }\n return this.refreshPromise;\n }\n\n override async signinResourceOwnerCredentials(_args: SigninResourceOwnerCredentialsArgs): Promise<User> {\n unsupported('Resource Owner Password Credentials');\n }\n\n override async removeUser(): Promise<void> {\n await this.waitForRenewal();\n await this.removeUserWithoutWaiting();\n }\n\n cancel(): Promise<void> {\n return Promise.resolve();\n }\n\n async dispose(): Promise<void> {\n this.stopSilentRenew();\n await this.disposePlatform();\n await this.waitForRenewal();\n await this.cancel();\n }\n\n protected performSilentSignin(args: SigninSilentArgs): Promise<User | null> {\n return super.signinSilent(args);\n }\n\n protected removeUserWithoutWaiting(): Promise<void> {\n return super.removeUser();\n }\n\n protected checkForAutomaticRenewal(): void {\n if (!this.settings.automaticSilentRenew || this.automaticRenewalPromise) return;\n const renewal = this.getValidUser();\n this.automaticRenewalPromise = renewal;\n void renewal\n .catch((error: unknown) =>\n this.events._raiseSilentRenewError(error instanceof Error ? error : new Error('Silent renewal failed')),\n )\n .finally(() => {\n if (this.automaticRenewalPromise === renewal) this.automaticRenewalPromise = undefined;\n });\n }\n\n protected abstract disposePlatform(): Promise<void>;\n\n private async waitForRenewal(): Promise<void> {\n await this.automaticRenewalPromise?.catch(() => undefined);\n await this.refreshPromise?.catch(() => undefined);\n }\n}\n"]}
@@ -1,34 +1,11 @@
1
- import { UserManager, type SigninPopupArgs, type SigninResourceOwnerCredentialsArgs, type SigninSilentArgs, type SignoutResponse, type SignoutPopupArgs, type User } from 'oidc-client-ts';
2
- import type { CapacitorOidcNativeOptions, CapacitorUserManagerSettings } from './definitions.js';
3
- export declare class CapacitorUserManager extends UserManager {
4
- private readonly storageNamespace;
5
- private automaticRenewalPromise?;
6
- private refreshPromise?;
7
- private appStateListener?;
8
- private constructor();
1
+ import { BaseCapacitorUserManager } from './base-capacitor-user-manager.js';
2
+ import { type ResolvedUserManagerConfiguration } from './configuration.js';
3
+ import type { CapacitorOidcNativeOptions, CapacitorUserManagerConfiguration, CapacitorUserManagerSettings } from './definitions.js';
4
+ export declare abstract class CapacitorUserManager extends BaseCapacitorUserManager {
5
+ static create(configuration: CapacitorUserManagerConfiguration): Promise<CapacitorUserManager>;
6
+ /** @deprecated Use the platform configuration object. */
9
7
  static create(settings: CapacitorUserManagerSettings, nativeOptions?: CapacitorOidcNativeOptions): Promise<CapacitorUserManager>;
10
- signin(args?: SigninPopupArgs): Promise<User>;
11
- signinPopup(args?: SigninPopupArgs): Promise<User>;
12
- signout(args?: SignoutPopupArgs): Promise<void>;
13
- signoutPopup(args?: SignoutPopupArgs): Promise<void>;
14
- private checkForAutomaticRenewal;
15
- getValidUser(minimumValiditySeconds?: number): Promise<User | null>;
16
- removeUser(): Promise<void>;
17
- signinSilent(args?: SigninSilentArgs): Promise<User | null>;
18
- private refresh;
19
- private waitForRenewal;
20
- storeUser(user: User | null): Promise<void>;
21
- cancel(): Promise<void>;
22
- dispose(): Promise<void>;
23
- signinRedirect(): Promise<void>;
24
- signinRedirectCallback(_url?: string): Promise<User>;
25
- signinCallback(_url?: string): Promise<User | undefined>;
26
- signinResourceOwnerCredentials(_args: SigninResourceOwnerCredentialsArgs): Promise<User>;
27
- signinSilentCallback(_url?: string): Promise<void>;
28
- signoutRedirect(): Promise<void>;
29
- signoutRedirectCallback(_url?: string): Promise<SignoutResponse>;
30
- signoutCallback(_url?: string, _keepOpen?: boolean): Promise<SignoutResponse | undefined>;
31
- signoutSilent(): Promise<void>;
32
- signoutSilentCallback(_url?: string): Promise<void>;
33
- querySessionStatus(): Promise<null>;
34
8
  }
9
+ type PlatformUserManagerFactory = (configuration: ResolvedUserManagerConfiguration) => CapacitorUserManager | Promise<CapacitorUserManager>;
10
+ export declare function setPlatformUserManagerFactory(factory: PlatformUserManagerFactory): void;
11
+ export {};
@@ -1,184 +1,30 @@
1
- import { App } from '@capacitor/app';
2
- import { ErrorResponse, UserManager, } from 'oidc-client-ts';
3
- import { CapacitorNavigator, UnsupportedIframeNavigator } from './capacitor-navigator.js';
4
- import { CapacitorSecureStateStore } from './capacitor-secure-state-store.js';
5
- import { CapacitorOidcError, unsupported } from './errors.js';
6
- import { NativeOidc } from './native.js';
7
- export class CapacitorUserManager extends UserManager {
8
- storageNamespace;
9
- automaticRenewalPromise;
10
- refreshPromise;
11
- appStateListener;
12
- constructor(settings, nativeOptions, storageNamespace) {
13
- const stateStore = new CapacitorSecureStateStore(`${storageNamespace}.transactions`);
14
- const userStore = new CapacitorSecureStateStore(`${storageNamespace}.session`);
15
- const navigator = new CapacitorNavigator(nativeOptions.prefersEphemeralWebBrowserSession ?? false);
16
- super({
17
- ...settings,
18
- response_type: 'code',
19
- disablePKCE: false,
20
- monitorSession: false,
21
- popup_redirect_uri: settings.redirect_uri,
22
- popup_post_logout_redirect_uri: settings.post_logout_redirect_uri,
23
- stateStore,
24
- userStore,
25
- }, navigator, navigator, new UnsupportedIframeNavigator());
26
- this.storageNamespace = storageNamespace;
27
- }
28
- static async create(settings, nativeOptions = {}) {
1
+ import { Capacitor } from '@capacitor/core';
2
+ import { BaseCapacitorUserManager } from './base-capacitor-user-manager.js';
3
+ import { resolveConfiguration, resolveLegacyNativeConfiguration, } from './configuration.js';
4
+ import { CapacitorOidcError } from './errors.js';
5
+ export class CapacitorUserManager extends BaseCapacitorUserManager {
6
+ static async create(configuration, nativeOptions = {}) {
29
7
  assertRuntime();
30
- assertSettings(settings);
31
- await NativeOidc.configure(nativeOptions.ios ?? {});
32
- const manager = new CapacitorUserManager(settings, nativeOptions, nativeOptions.storageNamespace ?? 'default');
33
- await manager.getUser();
34
- manager.appStateListener = await App.addListener('appStateChange', ({ isActive }) => {
35
- if (isActive) {
36
- manager.checkForAutomaticRenewal();
37
- }
38
- });
39
- manager.checkForAutomaticRenewal();
8
+ const platform = currentPlatform();
9
+ const resolved = 'redirect_uri' in configuration
10
+ ? resolveLegacyNativeConfiguration(configuration, nativeOptions, platform)
11
+ : resolveConfiguration(configuration, platform);
12
+ const manager = await platformUserManagerFactory(resolved);
13
+ await manager.initialize();
40
14
  return manager;
41
15
  }
42
- async signin(args = {}) {
43
- return this.signinPopup(args);
44
- }
45
- async signinPopup(args = {}) {
46
- await this.waitForRenewal();
47
- return super.signinPopup(args);
48
- }
49
- async signout(args = {}) {
50
- await this.signoutPopup(args);
51
- }
52
- async signoutPopup(args = {}) {
53
- await this.waitForRenewal();
54
- await super.signoutPopup(args);
55
- }
56
- checkForAutomaticRenewal() {
57
- if (!this.settings.automaticSilentRenew || this.automaticRenewalPromise)
58
- return;
59
- const renewal = this.getValidUser();
60
- this.automaticRenewalPromise = renewal;
61
- void renewal
62
- .catch((error) => this.events._raiseSilentRenewError(error instanceof Error ? error : new Error('Silent renewal failed')))
63
- .finally(() => {
64
- if (this.automaticRenewalPromise === renewal)
65
- this.automaticRenewalPromise = undefined;
66
- });
67
- }
68
- async getValidUser(minimumValiditySeconds = 60) {
69
- const user = await this.getUser();
70
- if (!user)
71
- return null;
72
- if (user.expires_in === undefined || user.expires_in > minimumValiditySeconds)
73
- return user;
74
- return this.signinSilent();
75
- }
76
- async removeUser() {
77
- await this.waitForRenewal();
78
- await super.removeUser();
79
- }
80
- signinSilent(args = {}) {
81
- if (!this.refreshPromise) {
82
- this.refreshPromise = this.refresh(args).finally(() => {
83
- this.refreshPromise = undefined;
84
- });
85
- }
86
- return this.refreshPromise;
87
- }
88
- async refresh(args) {
89
- const user = await this.getUser();
90
- if (!user?.refresh_token) {
91
- if (user?.expired)
92
- await super.removeUser();
93
- return null;
94
- }
95
- const refresh = super.signinSilent({ ...args, forceIframeAuth: false }).catch(async (error) => {
96
- if (error instanceof ErrorResponse && error.error === 'invalid_grant')
97
- await super.removeUser();
98
- throw error;
99
- });
100
- return refresh;
101
- }
102
- async waitForRenewal() {
103
- await this.automaticRenewalPromise?.catch(() => undefined);
104
- await this.refreshPromise?.catch(() => undefined);
105
- }
106
- async storeUser(user) {
107
- await super.storeUser(user);
108
- await NativeOidc.setSessionSnapshot({
109
- namespace: this.storageNamespace,
110
- value: user
111
- ? JSON.stringify(toStoredSession(user, user.profile.iss ?? this.settings.metadata?.issuer ?? this.settings.authority, this.settings.client_id))
112
- : null,
113
- });
114
- }
115
- async cancel() {
116
- await NativeOidc.cancel();
117
- }
118
- async dispose() {
119
- this.stopSilentRenew();
120
- await this.appStateListener?.remove();
121
- await this.waitForRenewal();
122
- await this.cancel();
123
- }
124
- async signinRedirect() {
125
- unsupported('Redirect navigation');
126
- }
127
- async signinRedirectCallback(_url) {
128
- unsupported('Redirect navigation');
129
- }
130
- async signinCallback(_url) {
131
- unsupported('Browser callback dispatch');
132
- }
133
- async signinResourceOwnerCredentials(_args) {
134
- unsupported('Resource Owner Password Credentials');
135
- }
136
- async signinSilentCallback(_url) {
137
- unsupported('Iframe navigation');
138
- }
139
- async signoutRedirect() {
140
- unsupported('Redirect navigation');
141
- }
142
- async signoutRedirectCallback(_url) {
143
- unsupported('Redirect navigation');
144
- }
145
- async signoutCallback(_url, _keepOpen) {
146
- unsupported('Browser callback dispatch');
147
- }
148
- async signoutSilent() {
149
- unsupported('Iframe logout');
150
- }
151
- async signoutSilentCallback(_url) {
152
- unsupported('Iframe logout');
153
- }
154
- async querySessionStatus() {
155
- unsupported('Browser session monitoring');
156
- }
16
+ }
17
+ let platformUserManagerFactory;
18
+ export function setPlatformUserManagerFactory(factory) {
19
+ platformUserManagerFactory = factory;
20
+ }
21
+ function currentPlatform() {
22
+ const platform = Capacitor.getPlatform();
23
+ return platform === 'ios' || platform === 'android' ? platform : 'web';
157
24
  }
158
25
  function assertRuntime() {
159
26
  if (!globalThis.crypto?.subtle || !globalThis.crypto.getRandomValues) {
160
27
  throw new CapacitorOidcError('UNSUPPORTED_RUNTIME', 'Web Crypto is required by oidc-client-ts');
161
28
  }
162
29
  }
163
- function assertSettings(settings) {
164
- if ('client_secret' in settings) {
165
- throw new CapacitorOidcError('UNSUPPORTED_RUNTIME', 'Native public clients must not contain a client secret');
166
- }
167
- if ('client_authentication' in settings || 'dpop' in settings) {
168
- throw new CapacitorOidcError('UNSUPPORTED_RUNTIME', 'The supplied settings contain an unsupported native-client option');
169
- }
170
- }
171
- function toStoredSession(user, issuer, clientId) {
172
- return {
173
- version: 1,
174
- issuer,
175
- clientId,
176
- accessToken: user.access_token,
177
- refreshToken: user.refresh_token,
178
- idToken: user.id_token,
179
- tokenType: user.token_type,
180
- scope: user.scope,
181
- expiresAt: user.expires_at,
182
- };
183
- }
184
30
  //# sourceMappingURL=capacitor-user-manager.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"capacitor-user-manager.js","sourceRoot":"","sources":["../../src/capacitor-user-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import { App } from '@capacitor/app';\nimport type { PluginListenerHandle } from '@capacitor/core';\nimport {\n ErrorResponse,\n UserManager,\n type SigninPopupArgs,\n type SigninResourceOwnerCredentialsArgs,\n type SigninSilentArgs,\n type SignoutResponse,\n type SignoutPopupArgs,\n type User,\n} from 'oidc-client-ts';\n\nimport { CapacitorNavigator, UnsupportedIframeNavigator } from './capacitor-navigator.js';\nimport { CapacitorSecureStateStore } from './capacitor-secure-state-store.js';\nimport type { CapacitorOidcNativeOptions, CapacitorUserManagerSettings, StoredSessionV1 } from './definitions.js';\nimport { CapacitorOidcError, unsupported } from './errors.js';\nimport { NativeOidc } from './native.js';\n\nexport class CapacitorUserManager extends UserManager {\n private automaticRenewalPromise?: Promise<User | null>;\n private refreshPromise?: Promise<User | null>;\n private appStateListener?: PluginListenerHandle;\n\n private constructor(\n settings: CapacitorUserManagerSettings,\n nativeOptions: CapacitorOidcNativeOptions,\n private readonly storageNamespace: string,\n ) {\n const stateStore = new CapacitorSecureStateStore(`${storageNamespace}.transactions`);\n const userStore = new CapacitorSecureStateStore(`${storageNamespace}.session`);\n const navigator = new CapacitorNavigator(nativeOptions.prefersEphemeralWebBrowserSession ?? false);\n\n super(\n {\n ...settings,\n response_type: 'code',\n disablePKCE: false,\n monitorSession: false,\n popup_redirect_uri: settings.redirect_uri,\n popup_post_logout_redirect_uri: settings.post_logout_redirect_uri,\n stateStore,\n userStore,\n },\n navigator,\n navigator,\n new UnsupportedIframeNavigator(),\n );\n }\n\n static async create(\n settings: CapacitorUserManagerSettings,\n nativeOptions: CapacitorOidcNativeOptions = {},\n ): Promise<CapacitorUserManager> {\n assertRuntime();\n assertSettings(settings);\n await NativeOidc.configure(nativeOptions.ios ?? {});\n const manager = new CapacitorUserManager(settings, nativeOptions, nativeOptions.storageNamespace ?? 'default');\n await manager.getUser();\n manager.appStateListener = await App.addListener('appStateChange', ({ isActive }) => {\n if (isActive) {\n manager.checkForAutomaticRenewal();\n }\n });\n manager.checkForAutomaticRenewal();\n return manager;\n }\n\n async signin(args: SigninPopupArgs = {}): Promise<User> {\n return this.signinPopup(args);\n }\n\n override async signinPopup(args: SigninPopupArgs = {}): Promise<User> {\n await this.waitForRenewal();\n return super.signinPopup(args);\n }\n\n async signout(args: SignoutPopupArgs = {}): Promise<void> {\n await this.signoutPopup(args);\n }\n\n override async signoutPopup(args: SignoutPopupArgs = {}): Promise<void> {\n await this.waitForRenewal();\n await super.signoutPopup(args);\n }\n\n private checkForAutomaticRenewal(): void {\n if (!this.settings.automaticSilentRenew || this.automaticRenewalPromise) return;\n const renewal = this.getValidUser();\n this.automaticRenewalPromise = renewal;\n void renewal\n .catch((error: unknown) =>\n this.events._raiseSilentRenewError(error instanceof Error ? error : new Error('Silent renewal failed')),\n )\n .finally(() => {\n if (this.automaticRenewalPromise === renewal) this.automaticRenewalPromise = undefined;\n });\n }\n\n async getValidUser(minimumValiditySeconds = 60): Promise<User | null> {\n const user = await this.getUser();\n if (!user) return null;\n if (user.expires_in === undefined || user.expires_in > minimumValiditySeconds) return user;\n return this.signinSilent();\n }\n\n override async removeUser(): Promise<void> {\n await this.waitForRenewal();\n await super.removeUser();\n }\n\n override signinSilent(args: SigninSilentArgs = {}): Promise<User | null> {\n if (!this.refreshPromise) {\n this.refreshPromise = this.refresh(args).finally(() => {\n this.refreshPromise = undefined;\n });\n }\n return this.refreshPromise;\n }\n\n private async refresh(args: SigninSilentArgs): Promise<User | null> {\n const user = await this.getUser();\n if (!user?.refresh_token) {\n if (user?.expired) await super.removeUser();\n return null;\n }\n\n const refresh = super.signinSilent({ ...args, forceIframeAuth: false }).catch(async (error: unknown) => {\n if (error instanceof ErrorResponse && error.error === 'invalid_grant') await super.removeUser();\n throw error;\n });\n return refresh;\n }\n\n private async waitForRenewal(): Promise<void> {\n await this.automaticRenewalPromise?.catch(() => undefined);\n await this.refreshPromise?.catch(() => undefined);\n }\n\n override async storeUser(user: User | null): Promise<void> {\n await super.storeUser(user);\n await NativeOidc.setSessionSnapshot({\n namespace: this.storageNamespace,\n value: user\n ? JSON.stringify(\n toStoredSession(\n user,\n user.profile.iss ?? this.settings.metadata?.issuer ?? this.settings.authority,\n this.settings.client_id,\n ),\n )\n : null,\n });\n }\n\n async cancel(): Promise<void> {\n await NativeOidc.cancel();\n }\n\n async dispose(): Promise<void> {\n this.stopSilentRenew();\n await this.appStateListener?.remove();\n await this.waitForRenewal();\n await this.cancel();\n }\n\n override async signinRedirect(): Promise<void> {\n unsupported('Redirect navigation');\n }\n\n override async signinRedirectCallback(_url?: string): Promise<User> {\n unsupported('Redirect navigation');\n }\n\n override async signinCallback(_url?: string): Promise<User | undefined> {\n unsupported('Browser callback dispatch');\n }\n\n override async signinResourceOwnerCredentials(_args: SigninResourceOwnerCredentialsArgs): Promise<User> {\n unsupported('Resource Owner Password Credentials');\n }\n\n override async signinSilentCallback(_url?: string): Promise<void> {\n unsupported('Iframe navigation');\n }\n\n override async signoutRedirect(): Promise<void> {\n unsupported('Redirect navigation');\n }\n\n override async signoutRedirectCallback(_url?: string): Promise<SignoutResponse> {\n unsupported('Redirect navigation');\n }\n\n override async signoutCallback(_url?: string, _keepOpen?: boolean): Promise<SignoutResponse | undefined> {\n unsupported('Browser callback dispatch');\n }\n\n override async signoutSilent(): Promise<void> {\n unsupported('Iframe logout');\n }\n\n override async signoutSilentCallback(_url?: string): Promise<void> {\n unsupported('Iframe logout');\n }\n\n override async querySessionStatus(): Promise<null> {\n unsupported('Browser session monitoring');\n }\n}\n\nfunction assertRuntime(): void {\n if (!globalThis.crypto?.subtle || !globalThis.crypto.getRandomValues) {\n throw new CapacitorOidcError('UNSUPPORTED_RUNTIME', 'Web Crypto is required by oidc-client-ts');\n }\n}\n\nfunction assertSettings(settings: CapacitorUserManagerSettings): void {\n if ('client_secret' in settings) {\n throw new CapacitorOidcError('UNSUPPORTED_RUNTIME', 'Native public clients must not contain a client secret');\n }\n if ('client_authentication' in settings || 'dpop' in settings) {\n throw new CapacitorOidcError(\n 'UNSUPPORTED_RUNTIME',\n 'The supplied settings contain an unsupported native-client option',\n );\n }\n}\n\nfunction toStoredSession(user: User, issuer: string, clientId: string): StoredSessionV1 {\n return {\n version: 1,\n issuer,\n clientId,\n accessToken: user.access_token,\n refreshToken: user.refresh_token,\n idToken: user.id_token,\n tokenType: user.token_type,\n scope: user.scope,\n expiresAt: user.expires_at,\n };\n}\n"]}
1
+ {"version":3,"file":"capacitor-user-manager.js","sourceRoot":"","sources":["../../src/capacitor-user-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,EACL,oBAAoB,EACpB,gCAAgC,GAGjC,MAAM,oBAAoB,CAAC;AAM5B,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD,MAAM,OAAgB,oBAAqB,SAAQ,wBAAwB;IAOzE,MAAM,CAAC,KAAK,CAAC,MAAM,CACjB,aAA+E,EAC/E,gBAA4C,EAAE;QAE9C,aAAa,EAAE,CAAC;QAChB,MAAM,QAAQ,GAAG,eAAe,EAAE,CAAC;QACnC,MAAM,QAAQ,GACZ,cAAc,IAAI,aAAa;YAC7B,CAAC,CAAC,gCAAgC,CAAC,aAAa,EAAE,aAAa,EAAE,QAAQ,CAAC;YAC1E,CAAC,CAAC,oBAAoB,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;QAEpD,MAAM,OAAO,GAAG,MAAM,0BAA0B,CAAC,QAAQ,CAAC,CAAC;QAC3D,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC;QAC3B,OAAO,OAAO,CAAC;IACjB,CAAC;CACF;AAMD,IAAI,0BAAsD,CAAC;AAE3D,MAAM,UAAU,6BAA6B,CAAC,OAAmC;IAC/E,0BAA0B,GAAG,OAAO,CAAC;AACvC,CAAC;AAED,SAAS,eAAe;IACtB,MAAM,QAAQ,GAAG,SAAS,CAAC,WAAW,EAAE,CAAC;IACzC,OAAO,QAAQ,KAAK,KAAK,IAAI,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;AACzE,CAAC;AAED,SAAS,aAAa;IACpB,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC;QACrE,MAAM,IAAI,kBAAkB,CAAC,qBAAqB,EAAE,0CAA0C,CAAC,CAAC;IAClG,CAAC;AACH,CAAC","sourcesContent":["import { Capacitor } from '@capacitor/core';\n\nimport { BaseCapacitorUserManager } from './base-capacitor-user-manager.js';\nimport {\n resolveConfiguration,\n resolveLegacyNativeConfiguration,\n type ResolvedUserManagerConfiguration,\n type RuntimePlatform,\n} from './configuration.js';\nimport type {\n CapacitorOidcNativeOptions,\n CapacitorUserManagerConfiguration,\n CapacitorUserManagerSettings,\n} from './definitions.js';\nimport { CapacitorOidcError } from './errors.js';\n\nexport abstract class CapacitorUserManager extends BaseCapacitorUserManager {\n static create(configuration: CapacitorUserManagerConfiguration): Promise<CapacitorUserManager>;\n /** @deprecated Use the platform configuration object. */\n static create(\n settings: CapacitorUserManagerSettings,\n nativeOptions?: CapacitorOidcNativeOptions,\n ): Promise<CapacitorUserManager>;\n static async create(\n configuration: CapacitorUserManagerConfiguration | CapacitorUserManagerSettings,\n nativeOptions: CapacitorOidcNativeOptions = {},\n ): Promise<CapacitorUserManager> {\n assertRuntime();\n const platform = currentPlatform();\n const resolved =\n 'redirect_uri' in configuration\n ? resolveLegacyNativeConfiguration(configuration, nativeOptions, platform)\n : resolveConfiguration(configuration, platform);\n\n const manager = await platformUserManagerFactory(resolved);\n await manager.initialize();\n return manager;\n }\n}\n\ntype PlatformUserManagerFactory = (\n configuration: ResolvedUserManagerConfiguration,\n) => CapacitorUserManager | Promise<CapacitorUserManager>;\n\nlet platformUserManagerFactory: PlatformUserManagerFactory;\n\nexport function setPlatformUserManagerFactory(factory: PlatformUserManagerFactory): void {\n platformUserManagerFactory = factory;\n}\n\nfunction currentPlatform(): RuntimePlatform {\n const platform = Capacitor.getPlatform();\n return platform === 'ios' || platform === 'android' ? platform : 'web';\n}\n\nfunction assertRuntime(): void {\n if (!globalThis.crypto?.subtle || !globalThis.crypto.getRandomValues) {\n throw new CapacitorOidcError('UNSUPPORTED_RUNTIME', 'Web Crypto is required by oidc-client-ts');\n }\n}\n"]}
@@ -0,0 +1,14 @@
1
+ import type { UserManagerSettings } from 'oidc-client-ts';
2
+ import type { CapacitorOidcNativeOptions, CapacitorSigninArgs, CapacitorSignoutArgs, CapacitorUserManagerConfiguration, CapacitorUserManagerSettings } from './definitions.js';
3
+ export type RuntimePlatform = 'android' | 'ios' | 'web';
4
+ export interface ResolvedUserManagerConfiguration {
5
+ platform: RuntimePlatform;
6
+ settings: UserManagerSettings;
7
+ nativeOptions?: CapacitorOidcNativeOptions;
8
+ signinMode: 'popup' | 'redirect';
9
+ signoutMode: 'popup' | 'redirect';
10
+ signinArgs: CapacitorSigninArgs;
11
+ signoutArgs: CapacitorSignoutArgs;
12
+ }
13
+ export declare function resolveConfiguration(configuration: CapacitorUserManagerConfiguration, platform: RuntimePlatform): ResolvedUserManagerConfiguration;
14
+ export declare function resolveLegacyNativeConfiguration(settings: CapacitorUserManagerSettings, nativeOptions: CapacitorOidcNativeOptions, platform: RuntimePlatform): ResolvedUserManagerConfiguration;