capacitor-oidc 0.0.6 → 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/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,35 +67,41 @@ 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
107
  [`example`](example).
package/SECURITY.md CHANGED
@@ -7,9 +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.
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.
13
14
 
14
15
  ## ID-token validation in `oidc-client-ts` 3.5.0
15
16
 
@@ -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":"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","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;
@@ -0,0 +1,72 @@
1
+ import { CapacitorOidcError } from './errors.js';
2
+ export function resolveConfiguration(configuration, platform) {
3
+ if (platform === 'web')
4
+ return resolveWebConfiguration(configuration);
5
+ return resolveNativeConfiguration(configuration, platform);
6
+ }
7
+ export function resolveLegacyNativeConfiguration(settings, nativeOptions, platform) {
8
+ if (platform === 'web') {
9
+ throw new CapacitorOidcError('UNSUPPORTED_RUNTIME', 'Legacy CapacitorUserManager settings are only supported on iOS and Android');
10
+ }
11
+ assertPublicClient(settings);
12
+ if ('dpop' in settings) {
13
+ throw new CapacitorOidcError('UNSUPPORTED_RUNTIME', 'Native configuration does not support dpop');
14
+ }
15
+ return resolvedNativeConfiguration(platform, settings, nativeOptions);
16
+ }
17
+ function resolveWebConfiguration(configuration) {
18
+ const web = configuration.web;
19
+ if (!web)
20
+ unsupportedConfiguration('web');
21
+ const signoutMode = web.signoutMode ?? 'redirect';
22
+ const settings = { ...configuration.common, ...web.settings };
23
+ assertPublicClient(settings);
24
+ if (signoutMode === 'popup' && !settings.popup_post_logout_redirect_uri && !settings.post_logout_redirect_uri) {
25
+ throw new CapacitorOidcError('UNSUPPORTED_RUNTIME', 'Web popup signout requires post_logout_redirect_uri or popup_post_logout_redirect_uri');
26
+ }
27
+ return {
28
+ platform: 'web',
29
+ settings,
30
+ signinMode: web.signinMode ?? 'redirect',
31
+ signoutMode,
32
+ signinArgs: web.signinArgs ?? {},
33
+ signoutArgs: web.signoutArgs ?? {},
34
+ };
35
+ }
36
+ function resolveNativeConfiguration(configuration, platform) {
37
+ const native = configuration.native;
38
+ if (!native)
39
+ unsupportedConfiguration(platform);
40
+ const override = configuration[platform];
41
+ const settings = { ...configuration.common, ...native.settings, ...override?.settings };
42
+ assertPublicClient(settings);
43
+ assertNativeSettings(settings);
44
+ return resolvedNativeConfiguration(platform, settings, { ...native.options, ...override?.options }, { ...native.signinArgs, ...override?.signinArgs }, { ...native.signoutArgs, ...override?.signoutArgs });
45
+ }
46
+ function resolvedNativeConfiguration(platform, settings, nativeOptions, signinArgs = {}, signoutArgs = {}) {
47
+ return {
48
+ platform,
49
+ settings: { ...settings, response_type: 'code', disablePKCE: false, monitorSession: false },
50
+ nativeOptions,
51
+ signinMode: 'popup',
52
+ signoutMode: 'popup',
53
+ signinArgs,
54
+ signoutArgs,
55
+ };
56
+ }
57
+ function assertPublicClient(settings) {
58
+ const unsupported = ['client_authentication', 'client_secret', 'disablePKCE', 'response_type'].find((key) => key in settings);
59
+ if (unsupported) {
60
+ throw new CapacitorOidcError('UNSUPPORTED_RUNTIME', `Public-client configuration does not support ${unsupported}`);
61
+ }
62
+ }
63
+ function assertNativeSettings(settings) {
64
+ const unsupported = ['dpop', 'monitorSession', 'silent_redirect_uri', 'stateStore', 'userStore'].find((key) => key in settings);
65
+ if (unsupported) {
66
+ throw new CapacitorOidcError('UNSUPPORTED_RUNTIME', `Native configuration does not support ${unsupported}`);
67
+ }
68
+ }
69
+ function unsupportedConfiguration(platform) {
70
+ throw new CapacitorOidcError('UNSUPPORTED_RUNTIME', `No ${platform} configuration was provided`);
71
+ }
72
+ //# sourceMappingURL=configuration.js.map