capacitor-oidc 0.0.1-alpha.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.
Files changed (44) hide show
  1. package/CapacitorOidc.podspec +17 -0
  2. package/LICENSE +201 -0
  3. package/Package.swift +28 -0
  4. package/README.md +122 -0
  5. package/android/build.gradle +75 -0
  6. package/android/src/main/AndroidManifest.xml +1 -0
  7. package/android/src/main/java/com/jojopirker/capacitor/oidc/CallbackUriMatcher.java +22 -0
  8. package/android/src/main/java/com/jojopirker/capacitor/oidc/CapacitorOidcPlugin.java +240 -0
  9. package/android/src/main/java/com/jojopirker/capacitor/oidc/NativeContract.java +35 -0
  10. package/android/src/main/java/com/jojopirker/capacitor/oidc/StoredSessionV1.java +111 -0
  11. package/android/src/main/java/com/jojopirker/capacitor/oidc/TokenVault.java +209 -0
  12. package/android/src/main/java/com/jojopirker/capacitor/oidc/VaultEntryCodec.java +56 -0
  13. package/dist/esm/capacitor-navigator.d.ts +14 -0
  14. package/dist/esm/capacitor-navigator.js +68 -0
  15. package/dist/esm/capacitor-navigator.js.map +1 -0
  16. package/dist/esm/capacitor-secure-state-store.d.ts +9 -0
  17. package/dist/esm/capacitor-secure-state-store.js +36 -0
  18. package/dist/esm/capacitor-secure-state-store.js.map +1 -0
  19. package/dist/esm/capacitor-user-manager.d.ts +28 -0
  20. package/dist/esm/capacitor-user-manager.js +160 -0
  21. package/dist/esm/capacitor-user-manager.js.map +1 -0
  22. package/dist/esm/definitions.d.ts +62 -0
  23. package/dist/esm/definitions.js +2 -0
  24. package/dist/esm/definitions.js.map +1 -0
  25. package/dist/esm/errors.d.ts +6 -0
  26. package/dist/esm/errors.js +13 -0
  27. package/dist/esm/errors.js.map +1 -0
  28. package/dist/esm/generated/native-contract.d.ts +37 -0
  29. package/dist/esm/generated/native-contract.js +38 -0
  30. package/dist/esm/generated/native-contract.js.map +1 -0
  31. package/dist/esm/index.d.ts +5 -0
  32. package/dist/esm/index.js +5 -0
  33. package/dist/esm/index.js.map +1 -0
  34. package/dist/esm/native.d.ts +2 -0
  35. package/dist/esm/native.js +4 -0
  36. package/dist/esm/native.js.map +1 -0
  37. package/dist/plugin.cjs +304 -0
  38. package/dist/plugin.cjs.map +1 -0
  39. package/ios/Sources/CapacitorOidcPlugin/CapacitorOidcPlugin.swift +177 -0
  40. package/ios/Sources/CapacitorOidcPlugin/NativeContract.generated.swift +39 -0
  41. package/ios/Sources/CapacitorOidcPlugin/StoredSessionV1.swift +35 -0
  42. package/ios/Sources/CapacitorOidcPlugin/TokenVault.swift +132 -0
  43. package/ios/Tests/CapacitorOidcPluginTests/StoredSessionV1Tests.swift +38 -0
  44. package/package.json +85 -0
@@ -0,0 +1,304 @@
1
+ 'use strict';
2
+
3
+ var app = require('@capacitor/app');
4
+ var oidcClientTs = require('oidc-client-ts');
5
+ var core = require('@capacitor/core');
6
+
7
+ // Generated by scripts/generate-native-contract.mjs. Do not edit.
8
+ const nativeContract = {
9
+ pluginName: 'CapacitorOidc',
10
+ fields: {
11
+ url: 'url',
12
+ callbackUrl: 'callbackUrl',
13
+ prefersEphemeralWebBrowserSession: 'prefersEphemeralWebBrowserSession',
14
+ keychainAccessGroup: 'keychainAccessGroup',
15
+ keychainAccessibility: 'keychainAccessibility',
16
+ namespace: 'namespace',
17
+ key: 'key',
18
+ value: 'value',
19
+ keys: 'keys',
20
+ },
21
+ errorCodes: {
22
+ browserUnavailable: 'BROWSER_UNAVAILABLE',
23
+ invalidCallback: 'INVALID_CALLBACK',
24
+ unsupportedRuntime: 'UNSUPPORTED_RUNTIME',
25
+ }};
26
+
27
+ class CapacitorOidcError extends Error {
28
+ code;
29
+ constructor(code, message) {
30
+ super(message);
31
+ this.code = code;
32
+ this.name = 'CapacitorOidcError';
33
+ }
34
+ }
35
+ function unsupported(feature) {
36
+ throw new CapacitorOidcError(nativeContract.errorCodes.unsupportedRuntime, `${feature} is not available in a native Capacitor runtime`);
37
+ }
38
+
39
+ const NativeOidc = core.registerPlugin(nativeContract.pluginName);
40
+
41
+ class CapacitorNavigator {
42
+ prefersEphemeralWebBrowserSession;
43
+ constructor(prefersEphemeralWebBrowserSession) {
44
+ this.prefersEphemeralWebBrowserSession = prefersEphemeralWebBrowserSession;
45
+ }
46
+ async prepare() {
47
+ return new CapacitorWindow(this.prefersEphemeralWebBrowserSession);
48
+ }
49
+ async callback() {
50
+ unsupported('Navigator callbacks');
51
+ }
52
+ }
53
+ class CapacitorWindow {
54
+ prefersEphemeralWebBrowserSession;
55
+ constructor(prefersEphemeralWebBrowserSession) {
56
+ this.prefersEphemeralWebBrowserSession = prefersEphemeralWebBrowserSession;
57
+ }
58
+ async navigate({ url }) {
59
+ assertSecureRequestUrl(url);
60
+ const callbackUrl = callbackUrlFromRequest(url);
61
+ const response = await NativeOidc.open({
62
+ [nativeContract.fields.url]: url,
63
+ [nativeContract.fields.callbackUrl]: callbackUrl,
64
+ [nativeContract.fields.prefersEphemeralWebBrowserSession]: this.prefersEphemeralWebBrowserSession,
65
+ });
66
+ if (!isExpectedCallback(response[nativeContract.fields.url], callbackUrl)) {
67
+ throw new CapacitorOidcError(nativeContract.errorCodes.invalidCallback, 'The authentication callback does not match the configured redirect URI');
68
+ }
69
+ return { url: response[nativeContract.fields.url] };
70
+ }
71
+ close() {
72
+ void NativeOidc.cancel();
73
+ }
74
+ }
75
+ function assertSecureRequestUrl(requestUrl) {
76
+ const url = new URL(requestUrl);
77
+ const isLocalDevelopment = url.hostname === 'localhost' || url.hostname === '127.0.0.1' || url.hostname === '[::1]';
78
+ if (url.protocol !== 'https:' && !isLocalDevelopment) {
79
+ throw new CapacitorOidcError(nativeContract.errorCodes.browserUnavailable, 'OIDC authorization and logout endpoints must use HTTPS');
80
+ }
81
+ }
82
+ function callbackUrlFromRequest(requestUrl) {
83
+ const url = new URL(requestUrl);
84
+ const callback = url.searchParams.get('redirect_uri') ?? url.searchParams.get('post_logout_redirect_uri');
85
+ if (!callback) {
86
+ throw new CapacitorOidcError(nativeContract.errorCodes.invalidCallback, 'The OIDC request does not contain a redirect URI');
87
+ }
88
+ return callback;
89
+ }
90
+ function isExpectedCallback(actualValue, expectedValue) {
91
+ const actual = new URL(actualValue);
92
+ const expected = new URL(expectedValue);
93
+ return (actual.protocol.toLowerCase() === expected.protocol.toLowerCase() &&
94
+ actual.host.toLowerCase() === expected.host.toLowerCase() &&
95
+ actual.pathname === expected.pathname);
96
+ }
97
+ class UnsupportedIframeNavigator {
98
+ async prepare() {
99
+ unsupported('Iframe navigation');
100
+ }
101
+ async callback() {
102
+ unsupported('Iframe navigation');
103
+ }
104
+ }
105
+
106
+ class CapacitorSecureStateStore {
107
+ namespace;
108
+ constructor(namespace) {
109
+ this.namespace = namespace;
110
+ }
111
+ async set(key, value) {
112
+ await NativeOidc.storageSet({
113
+ [nativeContract.fields.namespace]: this.namespace,
114
+ [nativeContract.fields.key]: key,
115
+ [nativeContract.fields.value]: value,
116
+ });
117
+ }
118
+ async get(key) {
119
+ const result = await NativeOidc.storageGet({
120
+ [nativeContract.fields.namespace]: this.namespace,
121
+ [nativeContract.fields.key]: key,
122
+ });
123
+ return result[nativeContract.fields.value];
124
+ }
125
+ async remove(key) {
126
+ const result = await NativeOidc.storageRemove({
127
+ [nativeContract.fields.namespace]: this.namespace,
128
+ [nativeContract.fields.key]: key,
129
+ });
130
+ return result[nativeContract.fields.value];
131
+ }
132
+ async getAllKeys() {
133
+ const result = await NativeOidc.storageGetAllKeys({
134
+ [nativeContract.fields.namespace]: this.namespace,
135
+ });
136
+ return result[nativeContract.fields.keys];
137
+ }
138
+ }
139
+
140
+ class CapacitorUserManager extends oidcClientTs.UserManager {
141
+ storageNamespace;
142
+ refreshPromise;
143
+ appStateListener;
144
+ constructor(settings, nativeOptions, storageNamespace) {
145
+ const stateStore = new CapacitorSecureStateStore(`${storageNamespace}.transactions`);
146
+ const userStore = new CapacitorSecureStateStore(`${storageNamespace}.session`);
147
+ const navigator = new CapacitorNavigator(nativeOptions.ios?.prefersEphemeralWebBrowserSession ?? false);
148
+ super({
149
+ ...settings,
150
+ response_type: 'code',
151
+ disablePKCE: false,
152
+ monitorSession: false,
153
+ popup_redirect_uri: settings.redirect_uri,
154
+ popup_post_logout_redirect_uri: settings.post_logout_redirect_uri,
155
+ stateStore,
156
+ userStore,
157
+ }, navigator, navigator, new UnsupportedIframeNavigator());
158
+ this.storageNamespace = storageNamespace;
159
+ }
160
+ static async create(settings, nativeOptions = {}) {
161
+ assertRuntime();
162
+ assertSettings(settings);
163
+ await NativeOidc.configure({
164
+ [nativeContract.fields.prefersEphemeralWebBrowserSession]: nativeOptions.ios?.prefersEphemeralWebBrowserSession,
165
+ [nativeContract.fields.keychainAccessGroup]: nativeOptions.ios?.keychainAccessGroup,
166
+ [nativeContract.fields.keychainAccessibility]: nativeOptions.ios?.keychainAccessibility,
167
+ });
168
+ const manager = new CapacitorUserManager(settings, nativeOptions, nativeOptions.storageNamespace ?? 'default');
169
+ await manager.getValidUser();
170
+ manager.appStateListener = await app.App.addListener('appStateChange', ({ isActive }) => {
171
+ if (isActive) {
172
+ void manager
173
+ .getValidUser()
174
+ .catch((error) => manager.events._raiseSilentRenewError(error instanceof Error ? error : new Error('Silent renewal failed')));
175
+ }
176
+ });
177
+ return manager;
178
+ }
179
+ async signin(args = {}) {
180
+ return super.signinPopup(args);
181
+ }
182
+ async signout(args = {}) {
183
+ await super.signoutPopup(args);
184
+ }
185
+ async getValidUser(minimumValiditySeconds = 60) {
186
+ const user = await this.getUser();
187
+ if (!user)
188
+ return null;
189
+ if (user.expires_in === undefined || user.expires_in > minimumValiditySeconds)
190
+ return user;
191
+ return this.signinSilent();
192
+ }
193
+ signinSilent(args = {}) {
194
+ if (!this.refreshPromise) {
195
+ this.refreshPromise = this.refresh(args).finally(() => {
196
+ this.refreshPromise = undefined;
197
+ });
198
+ }
199
+ return this.refreshPromise;
200
+ }
201
+ async refresh(args) {
202
+ const user = await this.getUser();
203
+ if (!user?.refresh_token) {
204
+ if (user?.expired)
205
+ await this.removeUser();
206
+ return null;
207
+ }
208
+ const refresh = super.signinSilent({ ...args, forceIframeAuth: false }).catch(async (error) => {
209
+ if (error instanceof oidcClientTs.ErrorResponse && error.error === 'invalid_grant')
210
+ await this.removeUser();
211
+ throw error;
212
+ });
213
+ return refresh;
214
+ }
215
+ async storeUser(user) {
216
+ await super.storeUser(user);
217
+ await NativeOidc.setSessionSnapshot({
218
+ [nativeContract.fields.namespace]: this.storageNamespace,
219
+ [nativeContract.fields.value]: user
220
+ ? JSON.stringify(toStoredSession(user, this.settings.authority, this.settings.client_id))
221
+ : null,
222
+ });
223
+ }
224
+ async cancel() {
225
+ await NativeOidc.cancel();
226
+ }
227
+ async dispose() {
228
+ this.stopSilentRenew();
229
+ await this.appStateListener?.remove();
230
+ await this.cancel();
231
+ }
232
+ async signinRedirect() {
233
+ unsupported('Redirect navigation');
234
+ }
235
+ async signinRedirectCallback(_url) {
236
+ unsupported('Redirect navigation');
237
+ }
238
+ async signinCallback(_url) {
239
+ unsupported('Browser callback dispatch');
240
+ }
241
+ async signinResourceOwnerCredentials(_args) {
242
+ unsupported('Resource Owner Password Credentials');
243
+ }
244
+ async signinSilentCallback(_url) {
245
+ unsupported('Iframe navigation');
246
+ }
247
+ async signoutRedirect() {
248
+ unsupported('Redirect navigation');
249
+ }
250
+ async signoutRedirectCallback(_url) {
251
+ unsupported('Redirect navigation');
252
+ }
253
+ async signoutCallback(_url, _keepOpen) {
254
+ unsupported('Browser callback dispatch');
255
+ }
256
+ async signoutSilent() {
257
+ unsupported('Iframe logout');
258
+ }
259
+ async signoutSilentCallback(_url) {
260
+ unsupported('Iframe logout');
261
+ }
262
+ async querySessionStatus() {
263
+ unsupported('Browser session monitoring');
264
+ }
265
+ }
266
+ function assertRuntime() {
267
+ if (!globalThis.crypto?.subtle || !globalThis.crypto.getRandomValues) {
268
+ throw new CapacitorOidcError(nativeContract.errorCodes.unsupportedRuntime, 'Web Crypto is required by oidc-client-ts');
269
+ }
270
+ }
271
+ function assertSettings(settings) {
272
+ if ('client_secret' in settings) {
273
+ throw new CapacitorOidcError(nativeContract.errorCodes.unsupportedRuntime, 'Native public clients must not contain a client secret');
274
+ }
275
+ if ('client_authentication' in settings || 'dpop' in settings) {
276
+ throw new CapacitorOidcError(nativeContract.errorCodes.unsupportedRuntime, 'The supplied settings contain an unsupported native-client option');
277
+ }
278
+ }
279
+ function toStoredSession(user, issuer, clientId) {
280
+ return {
281
+ version: 1,
282
+ issuer,
283
+ clientId,
284
+ accessToken: user.access_token,
285
+ refreshToken: user.refresh_token,
286
+ idToken: user.id_token,
287
+ tokenType: user.token_type,
288
+ scope: user.scope,
289
+ expiresAt: user.expires_at,
290
+ };
291
+ }
292
+
293
+ Object.defineProperty(exports, "User", {
294
+ enumerable: true,
295
+ get: function () { return oidcClientTs.User; }
296
+ });
297
+ Object.defineProperty(exports, "UserManagerEvents", {
298
+ enumerable: true,
299
+ get: function () { return oidcClientTs.UserManagerEvents; }
300
+ });
301
+ exports.CapacitorOidcError = CapacitorOidcError;
302
+ exports.CapacitorSecureStateStore = CapacitorSecureStateStore;
303
+ exports.CapacitorUserManager = CapacitorUserManager;
304
+ //# sourceMappingURL=plugin.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.cjs","sources":["esm/generated/native-contract.js","esm/errors.js","esm/native.js","esm/capacitor-navigator.js","esm/capacitor-secure-state-store.js","esm/capacitor-user-manager.js"],"sourcesContent":["// Generated by scripts/generate-native-contract.mjs. Do not edit.\nexport const nativeContract = {\n pluginName: 'CapacitorOidc',\n methods: {\n configure: 'configure',\n open: 'open',\n cancel: 'cancel',\n storageSet: 'storageSet',\n storageGet: 'storageGet',\n storageRemove: 'storageRemove',\n storageGetAllKeys: 'storageGetAllKeys',\n setSessionSnapshot: 'setSessionSnapshot',\n },\n fields: {\n url: 'url',\n callbackUrl: 'callbackUrl',\n prefersEphemeralWebBrowserSession: 'prefersEphemeralWebBrowserSession',\n keychainAccessGroup: 'keychainAccessGroup',\n keychainAccessibility: 'keychainAccessibility',\n namespace: 'namespace',\n key: 'key',\n value: 'value',\n keys: 'keys',\n },\n errorCodes: {\n authSessionInProgress: 'AUTH_SESSION_IN_PROGRESS',\n userCancelled: 'USER_CANCELLED',\n browserUnavailable: 'BROWSER_UNAVAILABLE',\n invalidCallback: 'INVALID_CALLBACK',\n secureStorageError: 'SECURE_STORAGE_ERROR',\n unsupportedRuntime: 'UNSUPPORTED_RUNTIME',\n },\n keychainAccessibility: {\n afterFirstUnlockThisDeviceOnly: 'afterFirstUnlockThisDeviceOnly',\n whenUnlockedThisDeviceOnly: 'whenUnlockedThisDeviceOnly',\n },\n};\n//# sourceMappingURL=native-contract.js.map","import { nativeContract } from './generated/native-contract';\nexport class CapacitorOidcError extends Error {\n code;\n constructor(code, message) {\n super(message);\n this.code = code;\n this.name = 'CapacitorOidcError';\n }\n}\nexport function unsupported(feature) {\n throw new CapacitorOidcError(nativeContract.errorCodes.unsupportedRuntime, `${feature} is not available in a native Capacitor runtime`);\n}\n//# sourceMappingURL=errors.js.map","import { registerPlugin } from '@capacitor/core';\nimport { nativeContract } from './generated/native-contract';\nexport const NativeOidc = registerPlugin(nativeContract.pluginName);\n//# sourceMappingURL=native.js.map","import { CapacitorOidcError, unsupported } from './errors';\nimport { nativeContract } from './generated/native-contract';\nimport { NativeOidc } from './native';\nexport class CapacitorNavigator {\n prefersEphemeralWebBrowserSession;\n constructor(prefersEphemeralWebBrowserSession) {\n this.prefersEphemeralWebBrowserSession = prefersEphemeralWebBrowserSession;\n }\n async prepare() {\n return new CapacitorWindow(this.prefersEphemeralWebBrowserSession);\n }\n async callback() {\n unsupported('Navigator callbacks');\n }\n}\nclass CapacitorWindow {\n prefersEphemeralWebBrowserSession;\n constructor(prefersEphemeralWebBrowserSession) {\n this.prefersEphemeralWebBrowserSession = prefersEphemeralWebBrowserSession;\n }\n async navigate({ url }) {\n assertSecureRequestUrl(url);\n const callbackUrl = callbackUrlFromRequest(url);\n const response = await NativeOidc.open({\n [nativeContract.fields.url]: url,\n [nativeContract.fields.callbackUrl]: callbackUrl,\n [nativeContract.fields.prefersEphemeralWebBrowserSession]: this.prefersEphemeralWebBrowserSession,\n });\n if (!isExpectedCallback(response[nativeContract.fields.url], callbackUrl)) {\n throw new CapacitorOidcError(nativeContract.errorCodes.invalidCallback, 'The authentication callback does not match the configured redirect URI');\n }\n return { url: response[nativeContract.fields.url] };\n }\n close() {\n void NativeOidc.cancel();\n }\n}\nexport function assertSecureRequestUrl(requestUrl) {\n const url = new URL(requestUrl);\n const isLocalDevelopment = url.hostname === 'localhost' || url.hostname === '127.0.0.1' || url.hostname === '[::1]';\n if (url.protocol !== 'https:' && !isLocalDevelopment) {\n throw new CapacitorOidcError(nativeContract.errorCodes.browserUnavailable, 'OIDC authorization and logout endpoints must use HTTPS');\n }\n}\nexport function callbackUrlFromRequest(requestUrl) {\n const url = new URL(requestUrl);\n const callback = url.searchParams.get('redirect_uri') ?? url.searchParams.get('post_logout_redirect_uri');\n if (!callback) {\n throw new CapacitorOidcError(nativeContract.errorCodes.invalidCallback, 'The OIDC request does not contain a redirect URI');\n }\n return callback;\n}\nexport function isExpectedCallback(actualValue, expectedValue) {\n const actual = new URL(actualValue);\n const expected = new URL(expectedValue);\n return (actual.protocol.toLowerCase() === expected.protocol.toLowerCase() &&\n actual.host.toLowerCase() === expected.host.toLowerCase() &&\n actual.pathname === expected.pathname);\n}\nexport class UnsupportedIframeNavigator {\n async prepare() {\n unsupported('Iframe navigation');\n }\n async callback() {\n unsupported('Iframe navigation');\n }\n}\n//# sourceMappingURL=capacitor-navigator.js.map","import { nativeContract } from './generated/native-contract';\nimport { NativeOidc } from './native';\nexport class CapacitorSecureStateStore {\n namespace;\n constructor(namespace) {\n this.namespace = namespace;\n }\n async set(key, value) {\n await NativeOidc.storageSet({\n [nativeContract.fields.namespace]: this.namespace,\n [nativeContract.fields.key]: key,\n [nativeContract.fields.value]: value,\n });\n }\n async get(key) {\n const result = await NativeOidc.storageGet({\n [nativeContract.fields.namespace]: this.namespace,\n [nativeContract.fields.key]: key,\n });\n return result[nativeContract.fields.value];\n }\n async remove(key) {\n const result = await NativeOidc.storageRemove({\n [nativeContract.fields.namespace]: this.namespace,\n [nativeContract.fields.key]: key,\n });\n return result[nativeContract.fields.value];\n }\n async getAllKeys() {\n const result = await NativeOidc.storageGetAllKeys({\n [nativeContract.fields.namespace]: this.namespace,\n });\n return result[nativeContract.fields.keys];\n }\n}\n//# sourceMappingURL=capacitor-secure-state-store.js.map","import { App } from '@capacitor/app';\nimport { ErrorResponse, UserManager, } from 'oidc-client-ts';\nimport { CapacitorNavigator, UnsupportedIframeNavigator } from './capacitor-navigator';\nimport { CapacitorSecureStateStore } from './capacitor-secure-state-store';\nimport { CapacitorOidcError, unsupported } from './errors';\nimport { nativeContract } from './generated/native-contract';\nimport { NativeOidc } from './native';\nexport class CapacitorUserManager extends UserManager {\n storageNamespace;\n refreshPromise;\n appStateListener;\n constructor(settings, nativeOptions, storageNamespace) {\n const stateStore = new CapacitorSecureStateStore(`${storageNamespace}.transactions`);\n const userStore = new CapacitorSecureStateStore(`${storageNamespace}.session`);\n const navigator = new CapacitorNavigator(nativeOptions.ios?.prefersEphemeralWebBrowserSession ?? false);\n super({\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 }, navigator, navigator, new UnsupportedIframeNavigator());\n this.storageNamespace = storageNamespace;\n }\n static async create(settings, nativeOptions = {}) {\n assertRuntime();\n assertSettings(settings);\n await NativeOidc.configure({\n [nativeContract.fields.prefersEphemeralWebBrowserSession]: nativeOptions.ios?.prefersEphemeralWebBrowserSession,\n [nativeContract.fields.keychainAccessGroup]: nativeOptions.ios?.keychainAccessGroup,\n [nativeContract.fields.keychainAccessibility]: nativeOptions.ios?.keychainAccessibility,\n });\n const manager = new CapacitorUserManager(settings, nativeOptions, nativeOptions.storageNamespace ?? 'default');\n await manager.getValidUser();\n manager.appStateListener = await App.addListener('appStateChange', ({ isActive }) => {\n if (isActive) {\n void manager\n .getValidUser()\n .catch((error) => manager.events._raiseSilentRenewError(error instanceof Error ? error : new Error('Silent renewal failed')));\n }\n });\n return manager;\n }\n async signin(args = {}) {\n return super.signinPopup(args);\n }\n async signout(args = {}) {\n await super.signoutPopup(args);\n }\n async getValidUser(minimumValiditySeconds = 60) {\n const user = await this.getUser();\n if (!user)\n return null;\n if (user.expires_in === undefined || user.expires_in > minimumValiditySeconds)\n return user;\n return this.signinSilent();\n }\n signinSilent(args = {}) {\n if (!this.refreshPromise) {\n this.refreshPromise = this.refresh(args).finally(() => {\n this.refreshPromise = undefined;\n });\n }\n return this.refreshPromise;\n }\n async refresh(args) {\n const user = await this.getUser();\n if (!user?.refresh_token) {\n if (user?.expired)\n await this.removeUser();\n return null;\n }\n const refresh = super.signinSilent({ ...args, forceIframeAuth: false }).catch(async (error) => {\n if (error instanceof ErrorResponse && error.error === 'invalid_grant')\n await this.removeUser();\n throw error;\n });\n return refresh;\n }\n async storeUser(user) {\n await super.storeUser(user);\n await NativeOidc.setSessionSnapshot({\n [nativeContract.fields.namespace]: this.storageNamespace,\n [nativeContract.fields.value]: user\n ? JSON.stringify(toStoredSession(user, this.settings.authority, this.settings.client_id))\n : null,\n });\n }\n async cancel() {\n await NativeOidc.cancel();\n }\n async dispose() {\n this.stopSilentRenew();\n await this.appStateListener?.remove();\n await this.cancel();\n }\n async signinRedirect() {\n unsupported('Redirect navigation');\n }\n async signinRedirectCallback(_url) {\n unsupported('Redirect navigation');\n }\n async signinCallback(_url) {\n unsupported('Browser callback dispatch');\n }\n async signinResourceOwnerCredentials(_args) {\n unsupported('Resource Owner Password Credentials');\n }\n async signinSilentCallback(_url) {\n unsupported('Iframe navigation');\n }\n async signoutRedirect() {\n unsupported('Redirect navigation');\n }\n async signoutRedirectCallback(_url) {\n unsupported('Redirect navigation');\n }\n async signoutCallback(_url, _keepOpen) {\n unsupported('Browser callback dispatch');\n }\n async signoutSilent() {\n unsupported('Iframe logout');\n }\n async signoutSilentCallback(_url) {\n unsupported('Iframe logout');\n }\n async querySessionStatus() {\n unsupported('Browser session monitoring');\n }\n}\nfunction assertRuntime() {\n if (!globalThis.crypto?.subtle || !globalThis.crypto.getRandomValues) {\n throw new CapacitorOidcError(nativeContract.errorCodes.unsupportedRuntime, 'Web Crypto is required by oidc-client-ts');\n }\n}\nfunction assertSettings(settings) {\n if ('client_secret' in settings) {\n throw new CapacitorOidcError(nativeContract.errorCodes.unsupportedRuntime, 'Native public clients must not contain a client secret');\n }\n if ('client_authentication' in settings || 'dpop' in settings) {\n throw new CapacitorOidcError(nativeContract.errorCodes.unsupportedRuntime, 'The supplied settings contain an unsupported native-client option');\n }\n}\nfunction toStoredSession(user, issuer, clientId) {\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//# sourceMappingURL=capacitor-user-manager.js.map"],"names":["registerPlugin","UserManager","App","ErrorResponse"],"mappings":"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"}
@@ -0,0 +1,177 @@
1
+ import AuthenticationServices
2
+ import Capacitor
3
+ import Foundation
4
+
5
+ @objc(CapacitorOidcPlugin)
6
+ public final class CapacitorOidcPlugin: CAPPlugin, CAPBridgedPlugin, ASWebAuthenticationPresentationContextProviding {
7
+ public let identifier = "CapacitorOidcPlugin"
8
+ public let jsName = NativeContract.pluginName
9
+ public let pluginMethods: [CAPPluginMethod] = [
10
+ CAPPluginMethod(name: NativeContract.Method.configure, returnType: CAPPluginReturnPromise),
11
+ CAPPluginMethod(name: NativeContract.Method.open, returnType: CAPPluginReturnPromise),
12
+ CAPPluginMethod(name: NativeContract.Method.cancel, returnType: CAPPluginReturnPromise),
13
+ CAPPluginMethod(name: NativeContract.Method.storageSet, returnType: CAPPluginReturnPromise),
14
+ CAPPluginMethod(name: NativeContract.Method.storageGet, returnType: CAPPluginReturnPromise),
15
+ CAPPluginMethod(name: NativeContract.Method.storageRemove, returnType: CAPPluginReturnPromise),
16
+ CAPPluginMethod(name: NativeContract.Method.storageGetAllKeys, returnType: CAPPluginReturnPromise),
17
+ CAPPluginMethod(name: NativeContract.Method.setSessionSnapshot, returnType: CAPPluginReturnPromise)
18
+ ]
19
+
20
+ private var accessGroup: String?
21
+ private var accessibility = TokenVaultAccessibility.afterFirstUnlockThisDeviceOnly
22
+ private var authenticationSession: ASWebAuthenticationSession?
23
+ private var authenticationCall: CAPPluginCall?
24
+
25
+ @objc public func configure(_ call: CAPPluginCall) {
26
+ accessGroup = call.getString(NativeContract.Field.keychainAccessGroup)
27
+ if call.getString(NativeContract.Field.keychainAccessibility) == NativeContract.KeychainAccessibility.whenUnlockedThisDeviceOnly {
28
+ accessibility = .whenUnlockedThisDeviceOnly
29
+ } else {
30
+ accessibility = .afterFirstUnlockThisDeviceOnly
31
+ }
32
+ call.resolve()
33
+ }
34
+
35
+ @objc public func open(_ call: CAPPluginCall) {
36
+ guard authenticationSession == nil else {
37
+ call.reject("An authentication session is already active", NativeContract.ErrorCode.authSessionInProgress)
38
+ return
39
+ }
40
+ guard let urlValue = call.getString(NativeContract.Field.url), let url = URL(string: urlValue),
41
+ let callbackValue = call.getString(NativeContract.Field.callbackUrl), let callbackURL = URL(string: callbackValue),
42
+ let scheme = callbackURL.scheme else {
43
+ call.reject("The authentication URL or callback URL is invalid", NativeContract.ErrorCode.invalidCallback)
44
+ return
45
+ }
46
+ guard isSecureRequestURL(url) else {
47
+ call.reject("The authentication URL must use HTTPS outside loopback development", NativeContract.ErrorCode.browserUnavailable)
48
+ return
49
+ }
50
+
51
+ let completion: ASWebAuthenticationSession.CompletionHandler = { [weak self] callbackURL, error in
52
+ DispatchQueue.main.async { self?.completeAuthentication(callbackURL: callbackURL, error: error) }
53
+ }
54
+
55
+ let session: ASWebAuthenticationSession
56
+ if #available(iOS 17.4, *), scheme.lowercased() == "https" {
57
+ guard let host = callbackURL.host else {
58
+ call.reject("The HTTPS callback URL has no host", NativeContract.ErrorCode.invalidCallback)
59
+ return
60
+ }
61
+ session = ASWebAuthenticationSession(
62
+ url: url,
63
+ callback: .https(host: host, path: callbackURL.path),
64
+ completionHandler: completion
65
+ )
66
+ } else {
67
+ guard scheme.lowercased() != "https" else {
68
+ call.reject("HTTPS callbacks require iOS 17.4 or newer", NativeContract.ErrorCode.browserUnavailable)
69
+ return
70
+ }
71
+ session = ASWebAuthenticationSession(url: url, callbackURLScheme: scheme, completionHandler: completion)
72
+ }
73
+
74
+ session.presentationContextProvider = self
75
+ session.prefersEphemeralWebBrowserSession = call.getBool(NativeContract.Field.prefersEphemeralWebBrowserSession) ?? false
76
+ authenticationCall = call
77
+ authenticationSession = session
78
+ guard session.start() else {
79
+ authenticationCall = nil
80
+ authenticationSession = nil
81
+ call.reject("The system authentication session could not start", NativeContract.ErrorCode.browserUnavailable)
82
+ return
83
+ }
84
+ }
85
+
86
+ @objc public func cancel(_ call: CAPPluginCall) {
87
+ let activeCall = authenticationCall
88
+ let activeSession = authenticationSession
89
+ authenticationCall = nil
90
+ authenticationSession = nil
91
+ activeSession?.cancel()
92
+ activeCall?.reject("The user cancelled authentication", NativeContract.ErrorCode.userCancelled)
93
+ call.resolve()
94
+ }
95
+
96
+ @objc public func storageSet(_ call: CAPPluginCall) {
97
+ guard let namespace = call.getString(NativeContract.Field.namespace), let key = call.getString(NativeContract.Field.key),
98
+ let value = call.getString(NativeContract.Field.value) else {
99
+ call.reject("Storage input is invalid", NativeContract.ErrorCode.secureStorageError)
100
+ return
101
+ }
102
+ resolveStorage(call) { try vault().set(namespace: namespace, key: key, value: value); return [:] }
103
+ }
104
+
105
+ @objc public func storageGet(_ call: CAPPluginCall) {
106
+ guard let namespace = call.getString(NativeContract.Field.namespace), let key = call.getString(NativeContract.Field.key) else {
107
+ call.reject("Storage input is invalid", NativeContract.ErrorCode.secureStorageError)
108
+ return
109
+ }
110
+ resolveStorage(call) { [NativeContract.Field.value: try vault().get(namespace: namespace, key: key) as Any] }
111
+ }
112
+
113
+ @objc public func storageRemove(_ call: CAPPluginCall) {
114
+ guard let namespace = call.getString(NativeContract.Field.namespace), let key = call.getString(NativeContract.Field.key) else {
115
+ call.reject("Storage input is invalid", NativeContract.ErrorCode.secureStorageError)
116
+ return
117
+ }
118
+ resolveStorage(call) { [NativeContract.Field.value: try vault().remove(namespace: namespace, key: key) as Any] }
119
+ }
120
+
121
+ @objc public func storageGetAllKeys(_ call: CAPPluginCall) {
122
+ guard let namespace = call.getString(NativeContract.Field.namespace) else {
123
+ call.reject("Storage input is invalid", NativeContract.ErrorCode.secureStorageError)
124
+ return
125
+ }
126
+ resolveStorage(call) { [NativeContract.Field.keys: try vault().getAllKeys(namespace: namespace)] }
127
+ }
128
+
129
+ @objc public func setSessionSnapshot(_ call: CAPPluginCall) {
130
+ guard let namespace = call.getString(NativeContract.Field.namespace) else {
131
+ call.reject("Storage input is invalid", NativeContract.ErrorCode.secureStorageError)
132
+ return
133
+ }
134
+ resolveStorage(call) {
135
+ try vault().setSessionSnapshot(namespace: namespace, value: call.getString(NativeContract.Field.value))
136
+ return [:]
137
+ }
138
+ }
139
+
140
+ public func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
141
+ bridge?.viewController?.view.window ?? ASPresentationAnchor()
142
+ }
143
+
144
+ private func completeAuthentication(callbackURL: URL?, error: Error?) {
145
+ let call = authenticationCall
146
+ authenticationCall = nil
147
+ authenticationSession = nil
148
+
149
+ if let sessionError = error as? ASWebAuthenticationSessionError, sessionError.code == .canceledLogin {
150
+ call?.reject("The user cancelled authentication", NativeContract.ErrorCode.userCancelled)
151
+ } else if error != nil {
152
+ call?.reject("The system authentication session failed", NativeContract.ErrorCode.browserUnavailable)
153
+ } else if let callbackURL {
154
+ call?.resolve([NativeContract.Field.url: callbackURL.absoluteString])
155
+ } else {
156
+ call?.reject("The authentication session returned no callback", NativeContract.ErrorCode.invalidCallback)
157
+ }
158
+ }
159
+
160
+ private func vault() -> TokenVault {
161
+ TokenVault(accessGroup: accessGroup, accessibility: accessibility)
162
+ }
163
+
164
+ private func isSecureRequestURL(_ url: URL) -> Bool {
165
+ if url.scheme?.lowercased() == "https" { return true }
166
+ guard url.scheme?.lowercased() == "http", let host = url.host?.lowercased() else { return false }
167
+ return host == "localhost" || host == "127.0.0.1" || host == "::1"
168
+ }
169
+
170
+ private func resolveStorage(_ call: CAPPluginCall, operation: () throws -> [String: Any]) {
171
+ do {
172
+ call.resolve(try operation())
173
+ } catch {
174
+ call.reject("Secure storage failed", NativeContract.ErrorCode.secureStorageError)
175
+ }
176
+ }
177
+ }
@@ -0,0 +1,39 @@
1
+ // Generated by scripts/generate-native-contract.mjs. Do not edit.
2
+
3
+ enum NativeContract {
4
+ static let pluginName = "CapacitorOidc"
5
+
6
+ enum Method {
7
+ static let configure = "configure"
8
+ static let open = "open"
9
+ static let cancel = "cancel"
10
+ static let storageSet = "storageSet"
11
+ static let storageGet = "storageGet"
12
+ static let storageRemove = "storageRemove"
13
+ static let storageGetAllKeys = "storageGetAllKeys"
14
+ static let setSessionSnapshot = "setSessionSnapshot"
15
+ }
16
+ enum Field {
17
+ static let url = "url"
18
+ static let callbackUrl = "callbackUrl"
19
+ static let prefersEphemeralWebBrowserSession = "prefersEphemeralWebBrowserSession"
20
+ static let keychainAccessGroup = "keychainAccessGroup"
21
+ static let keychainAccessibility = "keychainAccessibility"
22
+ static let namespace = "namespace"
23
+ static let key = "key"
24
+ static let value = "value"
25
+ static let keys = "keys"
26
+ }
27
+ enum ErrorCode {
28
+ static let authSessionInProgress = "AUTH_SESSION_IN_PROGRESS"
29
+ static let userCancelled = "USER_CANCELLED"
30
+ static let browserUnavailable = "BROWSER_UNAVAILABLE"
31
+ static let invalidCallback = "INVALID_CALLBACK"
32
+ static let secureStorageError = "SECURE_STORAGE_ERROR"
33
+ static let unsupportedRuntime = "UNSUPPORTED_RUNTIME"
34
+ }
35
+ enum KeychainAccessibility {
36
+ static let afterFirstUnlockThisDeviceOnly = "afterFirstUnlockThisDeviceOnly"
37
+ static let whenUnlockedThisDeviceOnly = "whenUnlockedThisDeviceOnly"
38
+ }
39
+ }
@@ -0,0 +1,35 @@
1
+ import Foundation
2
+
3
+ public struct StoredSessionV1: Codable, Equatable, Sendable {
4
+ public let version: Int
5
+ public let issuer: String
6
+ public let clientId: String
7
+ public let accessToken: String
8
+ public let refreshToken: String?
9
+ public let idToken: String?
10
+ public let tokenType: String
11
+ public let scope: String?
12
+ public let expiresAt: Int?
13
+
14
+ public init(
15
+ version: Int = 1,
16
+ issuer: String,
17
+ clientId: String,
18
+ accessToken: String,
19
+ refreshToken: String? = nil,
20
+ idToken: String? = nil,
21
+ tokenType: String,
22
+ scope: String? = nil,
23
+ expiresAt: Int? = nil
24
+ ) {
25
+ self.version = version
26
+ self.issuer = issuer
27
+ self.clientId = clientId
28
+ self.accessToken = accessToken
29
+ self.refreshToken = refreshToken
30
+ self.idToken = idToken
31
+ self.tokenType = tokenType
32
+ self.scope = scope
33
+ self.expiresAt = expiresAt
34
+ }
35
+ }