capacitor-oidc 0.0.1-alpha.2 → 0.0.2

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.
@@ -10,7 +10,7 @@ Pod::Spec.new do |spec|
10
10
  spec.license = package['license']
11
11
  spec.homepage = package['homepage']
12
12
  spec.author = package['author']
13
- spec.source = { git: repository_url, tag: spec.version.to_s }
13
+ spec.source = { git: repository_url, tag: "v#{spec.version}" }
14
14
  spec.source_files = 'ios/Sources/**/*.{swift,h,m,c,cc,mm,cpp}'
15
15
  spec.ios.deployment_target = '15.0'
16
16
  spec.dependency 'Capacitor', '>= 7.0'
package/README.md CHANGED
@@ -1,32 +1,44 @@
1
1
  # capacitor-oidc
2
2
 
3
- A small native Capacitor adapter for [`oidc-client-ts`](https://github.com/authts/oidc-client-ts).
3
+ [![npm](https://img.shields.io/npm/v/capacitor-oidc)](https://www.npmjs.com/package/capacitor-oidc)
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
+ [![license](https://img.shields.io/npm/l/capacitor-oidc)](LICENSE)
4
6
 
5
- > [!WARNING]
6
- > This package is not ready for production use. `oidc-client-ts` 3.5.0 does not validate the required ID-token `iss`, `aud`, and `exp` claims. See [Security](SECURITY.md).
7
+ Native OAuth 2.0 and OpenID Connect for Capacitor, powered by
8
+ [`oidc-client-ts`](https://github.com/authts/oidc-client-ts).
7
9
 
8
- The package keeps OAuth and OpenID Connect in `oidc-client-ts`. Its native code only presents system authentication UI and stores state securely:
10
+ `capacitor-oidc` adapts the familiar `UserManager` API to native iOS and Android
11
+ applications. It keeps protocol behavior in `oidc-client-ts` and adds only the
12
+ Capacitor-specific pieces:
9
13
 
10
- - iOS: `ASWebAuthenticationSession` and Keychain.
11
- - Android: Auth Tab with its Custom Tab fallback, plus AES-GCM protected storage with a key held by Android Keystore.
12
- - TypeScript: a native `INavigator`, secure `StateStore`, foreground refresh serialization, and a resume check.
14
+ - system authentication UI instead of an embedded WebView;
15
+ - secure native storage for OIDC transactions and sessions;
16
+ - refresh-token renewal when the app is active or resumes;
17
+ - a native-readable session snapshot for app widgets.
13
18
 
14
- It does not patch `fetch`, add native OIDC networking, accept client secrets, render authentication in a WebView, or implement iframe renewal.
19
+ On iOS, authentication uses `ASWebAuthenticationSession`. On Android, it uses
20
+ AndroidX Auth Tab with its Custom Tab fallback.
21
+
22
+ ## Requirements
23
+
24
+ - Capacitor 7 or 8
25
+ - iOS 15 or newer
26
+ - Android API 24 or newer
27
+ - Android compile SDK 36, Java 21, and a compatible Android Gradle Plugin
28
+ - an OAuth public client using Authorization Code Flow with PKCE
29
+ - Web Crypto in the packaged Capacitor WebView
30
+ - CORS support for the app's Capacitor origin on OIDC HTTP endpoints
31
+
32
+ Never ship a client secret in a Capacitor application.
15
33
 
16
34
  ## Install
17
35
 
18
36
  ```sh
19
- npm install capacitor-oidc oidc-client-ts @capacitor/app
37
+ npm install capacitor-oidc @capacitor/app
20
38
  npx cap sync
21
39
  ```
22
40
 
23
- The package supports Capacitor 7 and newer.
24
-
25
- All discovery, token, refresh, UserInfo, and revocation requests use normal WebView `fetch`. The provider must allow the app's configured Capacitor origin through CORS.
26
-
27
- Authorization and logout endpoints must use HTTPS. Plain HTTP is accepted only for loopback local development.
28
-
29
- ## Usage
41
+ ## Quick start
30
42
 
31
43
  ```ts
32
44
  import { CapacitorUserManager } from 'capacitor-oidc';
@@ -42,96 +54,35 @@ const manager = await CapacitorUserManager.create(
42
54
  revokeTokensOnSignout: true,
43
55
  },
44
56
  {
45
- prefersEphemeralWebBrowserSession: false,
46
57
  storageNamespace: 'primary',
47
- ios: {
48
- keychainAccessGroup: 'TEAMID.group.com.example.app',
49
- keychainAccessibility: 'afterFirstUnlockThisDeviceOnly',
50
- },
51
58
  },
52
59
  );
53
60
 
54
61
  const user = await manager.signin();
55
62
  const validUser = await manager.getValidUser(30);
63
+
56
64
  await manager.signout();
57
65
  await manager.dispose();
58
66
  ```
59
67
 
60
- `automaticSilentRenew` uses `oidc-client-ts`'s foreground expiry timer. Native silent renewal uses a refresh token only and never falls back to an iframe. Concurrent renewal triggers share one request. Returning to the foreground calls `getValidUser()` so a token that expired while the app was suspended is refreshed.
61
-
62
- The operating system can suspend or terminate the app, so exact background refresh timing is not promised.
63
-
64
- ## Redirect setup
68
+ Register the redirect and post-logout redirect URIs exactly at your provider and
69
+ in the native application. The provider client must be public and must allow
70
+ Authorization Code Flow with PKCE.
65
71
 
66
- Register the redirect URI as a native public-client redirect at the provider. Never put a client secret in the app.
72
+ `CapacitorUserManager` is for native Capacitor runtimes. For a browser build, use
73
+ the normal `UserManager` from `oidc-client-ts` and select the implementation with
74
+ `Capacitor.isNativePlatform()` in the application.
67
75
 
68
- For an iOS custom scheme, add it to the application target's `CFBundleURLTypes`. HTTPS callbacks through `ASWebAuthenticationSession` require iOS 17.4 or newer and the appropriate Associated Domains configuration.
76
+ ## Documentation
69
77
 
70
- For an Android custom-scheme redirect, keep the host app's `MainActivity` in Capacitor's default `singleTask` launch mode and add this intent filter inside that existing activity declaration. This ensures callbacks from Auth Tab's Custom Tab fallback reach the plugin instance that opened the session. Replace the scheme with the one used by your redirect URI:
71
-
72
- ```xml
73
- <activity
74
- android:name=".MainActivity"
75
- android:launchMode="singleTask">
76
- <intent-filter>
77
- <action android:name="android.intent.action.VIEW" />
78
- <category android:name="android.intent.category.DEFAULT" />
79
- <category android:name="android.intent.category.BROWSABLE" />
80
- <data android:scheme="com.example.app" />
81
- </intent-filter>
82
- </activity>
83
- ```
84
-
85
- HTTPS callbacks require a verified App Link and Digital Asset Links. Auth Tab handles the result directly when the installed browser supports it and falls back to a Custom Tab on older browsers.
86
-
87
- Calling `cancel()` on Android rejects the pending JavaScript promise, but Android does not provide an API to forcibly close an already-open system Auth Tab or Custom Tab. Ephemeral browsing is requested on both platforms and may be ignored by an Android fallback browser.
88
-
89
- Provider-specific logout parameters remain available through `oidc-client-ts`. For Amazon Cognito, leave `post_logout_redirect_uri` unset in the manager settings and pass its `client_id` and `logout_uri` parameters when signing out:
90
-
91
- ```ts
92
- await manager.signout({
93
- extraQueryParams: {
94
- client_id: 'mobile-app',
95
- logout_uri: 'com.example.app:/logout-callback',
96
- },
97
- });
98
- ```
99
-
100
- ## Secure storage and widgets
101
-
102
- `userStore` and transaction `stateStore` are separate secure namespaces. Each successful user write also updates a versioned native `StoredSessionV1` snapshot. The snapshot is an eventually consistent widget cache, not the canonical OIDC session.
103
-
104
- An iOS app and WidgetKit extension can construct the public `TokenVault` with the same Keychain access group:
105
-
106
- ```swift
107
- let vault = TokenVault(accessGroup: "TEAMID.group.com.example.app")
108
- let session = try vault.loadSession(namespace: "primary")
109
- ```
110
-
111
- Replace `TEAMID` with the Apple Developer Team ID. Both targets must carry the same
112
- Keychain Sharing entitlement, normally declared as
113
- `$(AppIdentifierPrefix)group.com.example.app`; the runtime option uses its expanded
114
- `TEAMID.group.com.example.app` value. The default accessibility is
115
- `AfterFirstUnlockThisDeviceOnly`; Keychain synchronization and biometric gating are disabled.
116
-
117
- An Android app widget in the same package can use the public native vault:
118
-
119
- ```java
120
- TokenVault vault = new TokenVault(context);
121
- StoredSessionV1 session = vault.loadSession("primary");
122
- ```
123
-
124
- Widgets may read the current session. Autonomous native refresh is deliberately not implemented.
125
-
126
- ## Logout behavior
127
-
128
- `signout()` uses the provider's end-session endpoint in the same native authentication UI. If `revokeTokensOnSignout` is enabled, upstream revocation runs before local state is cleared. A revocation failure therefore preserves the local session and its renewal timer; after revocation succeeds, a later browser or callback failure leaves the app locally signed out. Removing the user cancels its expiry timer without disabling renewal for a later sign-in with the same manager.
129
-
130
- ## Unsupported APIs
131
-
132
- Use `signin()` and `signout()` for interactive flows. Redirect navigation, iframe logout, and browser session monitoring reject with `UNSUPPORTED_RUNTIME`. Resource Owner Password Credentials, DPoP, client secrets, exact background scheduling, and autonomous widget refresh are outside v1.
133
-
134
- Only one interactive native authentication session and one configured manager are supported at a time.
78
+ - [Getting started](docs/GETTING_STARTED.md)
79
+ - [iOS and Android setup](docs/PLATFORM_SETUP.md)
80
+ - [Provider configuration](docs/PROVIDERS.md)
81
+ - [API and `oidc-client-ts` compatibility](docs/API.md)
82
+ - [Sessions, secure storage, and widgets](docs/SESSIONS_AND_WIDGETS.md)
83
+ - [Troubleshooting](docs/TROUBLESHOOTING.md)
84
+ - [Testing status](docs/TESTING.md)
85
+ - [Security](SECURITY.md)
135
86
 
136
87
  ## Development
137
88
 
@@ -141,9 +92,9 @@ npm run verify:ios
141
92
  npm run verify:android
142
93
  ```
143
94
 
144
- Physical-device verification remains required for Web Crypto, system consent UI, redirects, and shared widget access before a production release. See [Testing](docs/TESTING.md) for the full matrix.
145
-
146
- See [Publishing](docs/PUBLISHING.md) for the guarded npm trusted-publishing setup and release process.
95
+ Architecture decisions and contributor constraints are documented in
96
+ [ARCHITECTURE.md](ARCHITECTURE.md), [REQUIREMENTS.md](REQUIREMENTS.md), and
97
+ [docs/adr](docs/adr).
147
98
 
148
99
  ## License
149
100
 
package/SECURITY.md CHANGED
@@ -7,25 +7,54 @@
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
- ## Known limitation in the pinned OIDC engine
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.
11
13
 
12
- This prerelease pins `oidc-client-ts` 3.5.0. Its ID-token response validation
13
- checks `sub`, `nonce`, and selected refresh-token continuity claims, but does not
14
- check the required `iss`, `aud`, and `exp` claims. The behavior is visible in the
15
- [v3.5.0 ResponseValidator](https://github.com/authts/oidc-client-ts/blob/v3.5.0/src/ResponseValidator.ts)
16
- and is tracked in [authts/oidc-client-ts#2475](https://github.com/authts/oidc-client-ts/issues/2475).
14
+ ## ID-token validation in `oidc-client-ts` 3.5.0
17
15
 
18
- The current alpha must not be treated as production-ready. Before a stable
19
- release, use an upstream version that performs the required validation and cover
20
- it with provider integration tests, or replace ADR 0001 with a different protocol
21
- engine decision. Do not add package-local JWT or cryptographic validation as a
22
- workaround.
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.
40
+
41
+ ## Secure-storage boundary
42
+
43
+ OIDC transactions and sessions are stored through iOS Keychain or an Android
44
+ Keystore-backed vault. Configuring an iOS Keychain access group gives every
45
+ entitled target access to the plugin's canonical session, transaction data, and
46
+ widget snapshot. Treat those extensions as part of the application's credential
47
+ trust boundary.
48
+
49
+ The widget snapshot can contain access, refresh, and ID tokens. Autonomous widget
50
+ refresh is not currently implemented; see
51
+ [Sessions, secure storage, and widgets](docs/SESSIONS_AND_WIDGETS.md).
23
52
 
24
53
  ## Runtime assumptions
25
54
 
26
55
  `oidc-client-ts` requires `crypto.subtle` and `crypto.getRandomValues`.
27
56
  `CapacitorUserManager.create()` rejects with `UNSUPPORTED_RUNTIME` when they are
28
- absent. Their presence and behavior must also be verified in packaged applications
29
- on physical iOS and Android devices.
57
+ absent. Their behavior must be verified in packaged applications on supported
58
+ physical devices.
30
59
 
31
- See [Testing](docs/TESTING.md) for the remaining device and provider coverage.
60
+ See [Testing](docs/TESTING.md) for current platform and provider coverage.
package/docs/API.md ADDED
@@ -0,0 +1,91 @@
1
+ # API and `oidc-client-ts` compatibility
2
+
3
+ `CapacitorUserManager` extends `UserManager` from `oidc-client-ts`. The adapter
4
+ adds a small native-friendly surface and preserves upstream session objects,
5
+ events, settings, refresh, UserInfo, and revocation behavior where they apply to
6
+ a native public client.
7
+
8
+ ## Added API
9
+
10
+ | API | Purpose |
11
+ | ------------------------------------------------------- | ------------------------------------------------------------------------ |
12
+ | `CapacitorUserManager.create(settings, nativeOptions?)` | Configures native storage and creates the manager. |
13
+ | `signin(args?)` | Runs interactive Authorization Code Flow with PKCE in system UI. |
14
+ | `signout(args?)` | Runs provider logout in system UI. |
15
+ | `getValidUser(minimumValiditySeconds?)` | Returns the user or performs one refresh-token renewal. |
16
+ | `cancel()` | Rejects the pending native session. |
17
+ | `dispose()` | Stops renewal, removes the app listener, and cancels pending navigation. |
18
+
19
+ Only one configured manager and one interactive native authentication session are
20
+ supported at a time.
21
+
22
+ ## Relevant inherited API
23
+
24
+ The following upstream APIs remain available:
25
+
26
+ - `getUser()`, `storeUser()`, and `removeUser()`;
27
+ - `signinSilent()` for refresh-token renewal;
28
+ - `revokeTokens()`;
29
+ - `startSilentRenew()` and `stopSilentRenew()`;
30
+ - `events`, including user-loaded, user-unloaded, token-expiring, token-expired,
31
+ and silent-renew-error events;
32
+ - the upstream `User`, profile, settings, metadata, UserInfo, and token response
33
+ types.
34
+
35
+ `signinPopup()` and `signoutPopup()` are inherited and use the native navigator,
36
+ but applications should prefer `signin()` and `signout()`.
37
+
38
+ ## Unsupported browser API
39
+
40
+ These inherited browser-oriented methods reject with `UNSUPPORTED_RUNTIME`:
41
+
42
+ - `signinRedirect()`, `signinRedirectCallback()`, and `signinCallback()`;
43
+ - `signinSilentCallback()` and iframe-based silent authentication;
44
+ - `signoutRedirect()`, `signoutRedirectCallback()`, and `signoutCallback()`;
45
+ - `signoutSilent()` and `signoutSilentCallback()`;
46
+ - `querySessionStatus()`;
47
+ - Resource Owner Password Credentials.
48
+
49
+ The native settings type excludes:
50
+
51
+ - `client_secret` and `client_authentication`;
52
+ - `disablePKCE` and `response_type`;
53
+ - `dpop`;
54
+ - `monitorSession` and `silent_redirect_uri`;
55
+ - custom `stateStore` and `userStore`.
56
+
57
+ The adapter forces Authorization Code Flow with PKCE, secure native stores, and
58
+ no iframe session monitoring.
59
+
60
+ ## Native options
61
+
62
+ ```ts
63
+ interface CapacitorOidcNativeOptions {
64
+ prefersEphemeralWebBrowserSession?: boolean;
65
+ storageNamespace?: string;
66
+ ios?: {
67
+ keychainAccessGroup?: string;
68
+ keychainAccessibility?: 'afterFirstUnlockThisDeviceOnly' | 'whenUnlockedThisDeviceOnly';
69
+ };
70
+ }
71
+ ```
72
+
73
+ `storageNamespace` defaults to `default`. Use a stable, application-specific
74
+ value and do not change it between releases unless intentionally starting a new
75
+ session store.
76
+
77
+ ## Adapter error codes
78
+
79
+ | Code | Meaning |
80
+ | -------------------------- | ------------------------------------------------------------------------ |
81
+ | `AUTH_SESSION_IN_PROGRESS` | Another native login or logout is active. |
82
+ | `USER_CANCELLED` | The user or application cancelled the system session. |
83
+ | `BROWSER_UNAVAILABLE` | No compatible browser exists or the request endpoint is insecure. |
84
+ | `INVALID_CALLBACK` | The callback is absent, malformed, or does not match the configured URI. |
85
+ | `SECURE_STORAGE_ERROR` | Keychain or Keystore-backed storage failed. |
86
+ | `UNSUPPORTED_RUNTIME` | Web Crypto is unavailable or a browser-only API was called. |
87
+
88
+ OAuth and OIDC server errors remain upstream `oidc-client-ts` errors.
89
+
90
+ For the complete upstream model and event API, use the
91
+ [`oidc-client-ts` documentation](https://authts.github.io/oidc-client-ts/).
@@ -0,0 +1,132 @@
1
+ # Getting started
2
+
3
+ ## 1. Configure a public client
4
+
5
+ Create a native or public client at your identity provider with:
6
+
7
+ - Authorization Code Flow enabled;
8
+ - PKCE with the `S256` challenge method;
9
+ - no client secret;
10
+ - an exact native redirect URI, such as `com.example.app:/callback`;
11
+ - an exact post-logout redirect URI when the provider supports one;
12
+ - the `openid` scope and any application scopes you need;
13
+ - a refresh-token or offline-access grant if the app must renew sessions.
14
+
15
+ The redirect URI must be registered at the provider and in the native app. A
16
+ minor difference in scheme, host, path, casing, or slash placement can prevent
17
+ the callback from completing.
18
+
19
+ ## 2. Install the package
20
+
21
+ ```sh
22
+ npm install capacitor-oidc @capacitor/app
23
+ npx cap sync
24
+ ```
25
+
26
+ Complete the [iOS or Android setup](PLATFORM_SETUP.md) before running the app.
27
+
28
+ ## 3. Create one manager
29
+
30
+ Create and retain one manager for the application session. Recreating managers
31
+ for individual API calls also recreates listeners and can produce competing
32
+ renewal work.
33
+
34
+ ```ts
35
+ import { CapacitorUserManager } from 'capacitor-oidc';
36
+
37
+ export const auth = await CapacitorUserManager.create(
38
+ {
39
+ authority: 'https://identity.example.com',
40
+ client_id: 'mobile-app',
41
+ redirect_uri: 'com.example.app:/callback',
42
+ post_logout_redirect_uri: 'com.example.app:/logout-callback',
43
+ scope: 'openid profile offline_access',
44
+ automaticSilentRenew: true,
45
+ loadUserInfo: true,
46
+ revokeTokensOnSignout: true,
47
+ },
48
+ {
49
+ prefersEphemeralWebBrowserSession: false,
50
+ storageNamespace: 'primary',
51
+ },
52
+ );
53
+ ```
54
+
55
+ `prefersEphemeralWebBrowserSession` defaults to `false`, allowing the system
56
+ browser to reuse an existing provider session. Set it to `true` when an isolated
57
+ session is more important than shared SSO. Android fallback browsers may ignore
58
+ the preference.
59
+
60
+ The current alpha restores the stored user during `create()`. If that user needs
61
+ immediate renewal and the device is offline, manager creation can reject. This
62
+ behavior is tracked for improvement; applications should currently initialize
63
+ the manager where they can present an authentication or connectivity error.
64
+
65
+ ## 4. Sign in
66
+
67
+ ```ts
68
+ const user = await auth.signin();
69
+
70
+ console.log(user.profile.sub);
71
+ ```
72
+
73
+ The promise resolves after the system authentication session returns to the app,
74
+ the authorization response is validated, and the code is exchanged.
75
+
76
+ Listen for session changes through the normal `oidc-client-ts` events:
77
+
78
+ ```ts
79
+ auth.events.addUserLoaded((user) => {
80
+ console.log('Signed in as', user.profile.sub);
81
+ });
82
+
83
+ auth.events.addSilentRenewError((error) => {
84
+ console.error('Token renewal failed', error);
85
+ });
86
+ ```
87
+
88
+ ## 5. Get a usable access token
89
+
90
+ ```ts
91
+ const user = await auth.getValidUser(30);
92
+
93
+ if (!user) {
94
+ // No signed-in session is available.
95
+ } else {
96
+ await fetch('https://api.example.com/profile', {
97
+ headers: { Authorization: `Bearer ${user.access_token}` },
98
+ });
99
+ }
100
+ ```
101
+
102
+ `getValidUser(30)` returns the current user when its access token is valid for at
103
+ least 30 more seconds. Otherwise it performs one refresh-token renewal. Concurrent
104
+ renewal triggers share the same request.
105
+
106
+ ## 6. Sign out
107
+
108
+ ```ts
109
+ await auth.signout();
110
+ ```
111
+
112
+ `signout()` opens the provider's end-session endpoint in the same native system
113
+ authentication UI. Provider-specific parameters can be passed through
114
+ `extraQueryParams`; see [Provider configuration](PROVIDERS.md).
115
+
116
+ Use `removeUser()` when the application intentionally needs local-only logout.
117
+
118
+ ## 7. Dispose application listeners
119
+
120
+ ```ts
121
+ await auth.dispose();
122
+ ```
123
+
124
+ Call `dispose()` when the manager will no longer be used. It stops silent renewal,
125
+ removes the Capacitor app-state listener, and cancels a pending native session.
126
+
127
+ ## Browser builds
128
+
129
+ `CapacitorUserManager` depends on native Capacitor plugins and is not a web
130
+ replacement for `UserManager`. Applications that also run in a normal browser
131
+ should instantiate `UserManager` from `oidc-client-ts` for the web branch and
132
+ `CapacitorUserManager` for the native branch.
@@ -0,0 +1,98 @@
1
+ # iOS and Android setup
2
+
3
+ ## iOS
4
+
5
+ The package supports iOS 15 and newer. Interactive login and logout use
6
+ `ASWebAuthenticationSession`, including the operating system's provider-consent
7
+ dialog and sheet presentation.
8
+
9
+ ### Custom-scheme callback
10
+
11
+ For `com.example.app:/callback`, register `com.example.app` in the application
12
+ target's `Info.plist`:
13
+
14
+ ```xml
15
+ <key>CFBundleURLTypes</key>
16
+ <array>
17
+ <dict>
18
+ <key>CFBundleURLSchemes</key>
19
+ <array>
20
+ <string>com.example.app</string>
21
+ </array>
22
+ </dict>
23
+ </array>
24
+ ```
25
+
26
+ Use an application-specific scheme that your organization controls. Register the
27
+ complete URI at the provider.
28
+
29
+ ### HTTPS callback
30
+
31
+ HTTPS callbacks through `ASWebAuthenticationSession` require iOS 17.4 or newer.
32
+ Configure the appropriate Associated Domains entitlement and association file,
33
+ then register the exact HTTPS callback at the provider.
34
+
35
+ ### Shared Keychain access
36
+
37
+ To let an iOS widget read the stored session, add the same Keychain Sharing
38
+ entitlement to the application and extension, then configure the expanded access
39
+ group:
40
+
41
+ ```ts
42
+ const manager = await CapacitorUserManager.create(settings, {
43
+ ios: {
44
+ keychainAccessGroup: 'TEAMID.group.com.example.app',
45
+ keychainAccessibility: 'afterFirstUnlockThisDeviceOnly',
46
+ },
47
+ storageNamespace: 'primary',
48
+ });
49
+ ```
50
+
51
+ See [Sessions, secure storage, and widgets](SESSIONS_AND_WIDGETS.md) before
52
+ enabling shared access.
53
+
54
+ ## Android
55
+
56
+ The Android adapter supports API 24 and newer. It is currently built and tested
57
+ with compile SDK 36, Android Gradle Plugin 8.9.1, Java 21, AndroidX Activity
58
+ 1.11.0, and AndroidX Browser 1.10.0. Capacitor 7 applications may therefore need
59
+ their Android toolchain upgraded even though the JavaScript peer dependency
60
+ allows Capacitor 7.
61
+
62
+ ### Custom-scheme callback
63
+
64
+ Keep the host application's existing `MainActivity` in Capacitor's default
65
+ `singleTask` launch mode. Add the callback intent filter inside that same activity
66
+ declaration:
67
+
68
+ ```xml
69
+ <activity
70
+ android:name=".MainActivity"
71
+ android:launchMode="singleTask">
72
+ <intent-filter>
73
+ <action android:name="android.intent.action.VIEW" />
74
+ <category android:name="android.intent.category.DEFAULT" />
75
+ <category android:name="android.intent.category.BROWSABLE" />
76
+ <data android:scheme="com.example.app" />
77
+ </intent-filter>
78
+ </activity>
79
+ ```
80
+
81
+ The `singleTask` activity receives callbacks from Auth Tab's Custom Tab fallback
82
+ through `onNewIntent`, allowing Capacitor to route the URL to the plugin instance
83
+ that opened the session.
84
+
85
+ ### HTTPS callback
86
+
87
+ Configure a verified Android App Link and publish a matching Digital Asset Links
88
+ file. Register the exact HTTPS URI at the identity provider.
89
+
90
+ ### Auth Tab behavior
91
+
92
+ AndroidX Auth Tab handles the result directly when the installed browser supports
93
+ it and falls back to a Custom Tab on older browsers. Calling `cancel()` rejects
94
+ the pending JavaScript promise, but Android does not expose an API that forcibly
95
+ closes an already-visible system Auth Tab or Custom Tab.
96
+
97
+ Ephemeral browsing is requested when configured and may be ignored by a fallback
98
+ browser.
@@ -0,0 +1,184 @@
1
+ # Provider configuration
2
+
3
+ `capacitor-oidc` works with providers that support Authorization Code Flow with
4
+ PKCE for public clients and permit token-related requests from the configured
5
+ Capacitor origin.
6
+
7
+ ## Provider checklist
8
+
9
+ For every provider:
10
+
11
+ 1. Create a native, mobile, SPA, or other public client. Do not create or embed a
12
+ client secret.
13
+ 2. Enable Authorization Code Flow and PKCE with `S256`.
14
+ 3. Register the native redirect and post-logout redirect URIs exactly.
15
+ 4. Enable refresh tokens and request the provider's offline-access scope if the
16
+ app must renew sessions.
17
+ 5. Allow the app's Capacitor origin through CORS for discovery, token, refresh,
18
+ UserInfo, and revocation endpoints used by your configuration.
19
+ 6. Use HTTPS for provider endpoints.
20
+
21
+ The recipes below identify the relevant authority and provider-console choices.
22
+ They do not replace the provider's own security guidance.
23
+
24
+ | Provider | Current package validation |
25
+ | ------------------ | --------------------------------------------------------------- |
26
+ | Amazon Cognito | Basic login tested on a physical iOS device; edge cases remain. |
27
+ | Auth0 | Configuration guidance only. |
28
+ | Keycloak | Configuration guidance only. |
29
+ | Okta | Configuration guidance only. |
30
+ | Microsoft Entra ID | Configuration guidance only. |
31
+
32
+ ## Amazon Cognito
33
+
34
+ Cognito separates the OIDC issuer from the managed-login domain. Use the user
35
+ pool issuer as `authority` and provide explicit metadata pointing browser-facing
36
+ endpoints at the managed-login domain:
37
+
38
+ ```ts
39
+ const region = 'eu-central-1';
40
+ const userPoolId = 'eu-central-1_example';
41
+ const clientId = 'public-client-id';
42
+ const domain = 'https://example.auth.eu-central-1.amazoncognito.com';
43
+ const issuer = `https://cognito-idp.${region}.amazonaws.com/${userPoolId}`;
44
+
45
+ const manager = await CapacitorUserManager.create({
46
+ authority: issuer,
47
+ client_id: clientId,
48
+ redirect_uri: 'com.example.app://oauth',
49
+ scope: 'openid email profile aws.cognito.signin.user.admin',
50
+ automaticSilentRenew: true,
51
+ revokeTokensOnSignout: true,
52
+ metadata: {
53
+ issuer,
54
+ authorization_endpoint: `${domain}/oauth2/authorize`,
55
+ token_endpoint: `${domain}/oauth2/token`,
56
+ userinfo_endpoint: `${domain}/oauth2/userInfo`,
57
+ revocation_endpoint: `${domain}/oauth2/revoke`,
58
+ end_session_endpoint: `${domain}/logout`,
59
+ jwks_uri: `${issuer}/.well-known/jwks.json`,
60
+ },
61
+ });
62
+ ```
63
+
64
+ Configure the Cognito app client without a secret and register
65
+ `com.example.app://oauth` as an allowed callback and sign-out URL.
66
+
67
+ Cognito logout uses `logout_uri` instead of the standard
68
+ `post_logout_redirect_uri`. Leave `post_logout_redirect_uri` unset in the manager
69
+ settings and pass Cognito's parameters when signing out:
70
+
71
+ ```ts
72
+ await manager.signout({
73
+ extraQueryParams: {
74
+ client_id: clientId,
75
+ logout_uri: 'com.example.app://oauth',
76
+ },
77
+ });
78
+ ```
79
+
80
+ See the AWS documentation for the
81
+ [authorization endpoint](https://docs.aws.amazon.com/cognito/latest/developerguide/authorization-endpoint.html),
82
+ [token endpoint](https://docs.aws.amazon.com/cognito/latest/developerguide/token-endpoint.html),
83
+ and [logout endpoint](https://docs.aws.amazon.com/cognito/latest/developerguide/logout-endpoint.html).
84
+
85
+ ## Auth0
86
+
87
+ Use the tenant or custom domain as the authority:
88
+
89
+ ```ts
90
+ const settings = {
91
+ authority: 'https://example.eu.auth0.com',
92
+ client_id: 'native-application-client-id',
93
+ redirect_uri: 'com.example.app:/callback',
94
+ post_logout_redirect_uri: 'com.example.app:/logout-callback',
95
+ scope: 'openid profile email offline_access',
96
+ automaticSilentRenew: true,
97
+ };
98
+ ```
99
+
100
+ Create a Native application, register both callback URLs, enable refresh-token
101
+ rotation as appropriate, and add the Capacitor origin to the allowed web origins
102
+ used for CORS.
103
+
104
+ See Auth0's [Capacitor quickstart](https://auth0.com/docs/quickstart/native/ionic-react)
105
+ and [refresh-token rotation guidance](https://auth0.com/docs/secure/tokens/refresh-tokens/refresh-token-rotation).
106
+
107
+ ## Keycloak
108
+
109
+ Use the realm URL as the authority:
110
+
111
+ ```ts
112
+ const settings = {
113
+ authority: 'https://identity.example.com/realms/example',
114
+ client_id: 'mobile-app',
115
+ redirect_uri: 'com.example.app:/callback',
116
+ post_logout_redirect_uri: 'com.example.app:/logout-callback',
117
+ scope: 'openid profile offline_access',
118
+ automaticSilentRenew: true,
119
+ };
120
+ ```
121
+
122
+ Create an OpenID Connect client with client authentication disabled, Standard
123
+ Flow enabled, an exact valid redirect URI, and the Capacitor origin in Web
124
+ Origins. Configure valid post-logout redirect URIs when using provider logout.
125
+
126
+ See the Keycloak documentation for
127
+ [managing OIDC clients](https://www.keycloak.org/docs/latest/server_admin/#_oidc_clients).
128
+
129
+ ## Okta
130
+
131
+ Use the authorization-server issuer as the authority. For the default custom
132
+ authorization server this commonly has the following form:
133
+
134
+ ```ts
135
+ const settings = {
136
+ authority: 'https://example.okta.com/oauth2/default',
137
+ client_id: 'native-application-client-id',
138
+ redirect_uri: 'com.example.app:/callback',
139
+ post_logout_redirect_uri: 'com.example.app:/logout-callback',
140
+ scope: 'openid profile offline_access',
141
+ automaticSilentRenew: true,
142
+ };
143
+ ```
144
+
145
+ Create a Native Application integration, require PKCE, and register exact sign-in
146
+ and sign-out redirect URIs.
147
+
148
+ See Okta's guide to
149
+ [signing users into a mobile app with redirect](https://developer.okta.com/docs/guides/sign-into-mobile-app-redirect/).
150
+
151
+ ## Microsoft Entra ID
152
+
153
+ Use a tenant-specific v2 issuer when the application belongs to one tenant:
154
+
155
+ ```ts
156
+ const settings = {
157
+ authority: 'https://login.microsoftonline.com/TENANT_ID/v2.0',
158
+ client_id: 'application-client-id',
159
+ redirect_uri: 'com.example.app:/callback',
160
+ post_logout_redirect_uri: 'com.example.app:/logout-callback',
161
+ scope: 'openid profile offline_access',
162
+ automaticSilentRenew: true,
163
+ };
164
+ ```
165
+
166
+ Configure a mobile and desktop application platform, register the native redirect
167
+ URI accepted by the app registration, and enable public-client flows required by
168
+ your tenant policy. Multi-tenant authorities and account selection require an
169
+ application-specific design rather than simply replacing `TENANT_ID` with a
170
+ shared authority.
171
+
172
+ See Microsoft Learn for
173
+ [mobile and desktop authentication flows](https://learn.microsoft.com/en-us/entra/identity-platform/scenario-desktop-overview)
174
+ and [redirect URI restrictions](https://learn.microsoft.com/en-us/entra/identity-platform/reply-url).
175
+
176
+ ## Other providers
177
+
178
+ Start with the generic checklist and the provider's OpenID Connect discovery
179
+ document. If discovery does not describe a usable native flow, pass explicit
180
+ `metadata` through the upstream `UserManagerSettings` rather than adding
181
+ provider-specific code to this package.
182
+
183
+ Provider-specific compatibility reports and tested configuration examples are
184
+ welcome as focused contributions.
@@ -71,11 +71,15 @@ Stable production releases additionally require the checks in
71
71
  3. Publish a GitHub release whose tag is exactly `vX.Y.Z` or `vX.Y.Z-prerelease`. Mark a prerelease version as a GitHub prerelease.
72
72
  4. Approve the `npm-production` deployment after its checks are visible.
73
73
 
74
- The workflow installs from the lockfile without a package-manager cache, verifies
75
- the package, inspects the tarball, and publishes it publicly under `latest` for a
76
- stable release or `next` for a prerelease. The job is skipped unless
77
- `NPM_PUBLISH_ENABLED` is exactly `true`. npm automatically generates provenance for
78
- a public package published from this public repository through a trusted publisher.
74
+ The workflow first installs from the lockfile without a package-manager cache,
75
+ verifies the package, and creates the release tarball in a job without OIDC
76
+ permissions. After that succeeds, the `npm-production` environment gates a separate
77
+ job that downloads and publishes only that tarball, with package scripts disabled.
78
+ The privileged job does not check out source, install dependencies, or run repository
79
+ build scripts. Stable releases use `latest`; prereleases use `next`. The workflow is
80
+ skipped unless `NPM_PUBLISH_ENABLED` is exactly `true`. npm automatically generates
81
+ provenance for a public package published from this public repository through a
82
+ trusted publisher.
79
83
 
80
84
  After the first trusted publication succeeds, configure npm to disallow traditional
81
85
  token publishing and revoke unused automation tokens. Trusted publishing continues
package/docs/README.md ADDED
@@ -0,0 +1,23 @@
1
+ # Documentation
2
+
3
+ `capacitor-oidc` is a native Capacitor adapter for `oidc-client-ts`. Start with
4
+ [Getting started](GETTING_STARTED.md), then complete the setup for both your
5
+ native platform and identity provider.
6
+
7
+ ## Use the package
8
+
9
+ - [Getting started](GETTING_STARTED.md)
10
+ - [iOS and Android setup](PLATFORM_SETUP.md)
11
+ - [Provider configuration](PROVIDERS.md)
12
+ - [API and `oidc-client-ts` compatibility](API.md)
13
+ - [Sessions, secure storage, and widgets](SESSIONS_AND_WIDGETS.md)
14
+ - [Troubleshooting](TROUBLESHOOTING.md)
15
+ - [Security](../SECURITY.md)
16
+
17
+ ## Contribute and release
18
+
19
+ - [Architecture](../ARCHITECTURE.md)
20
+ - [Requirements and acceptance criteria](../REQUIREMENTS.md)
21
+ - [Testing](TESTING.md)
22
+ - [Publishing](PUBLISHING.md)
23
+ - [Architecture decisions](adr)
@@ -0,0 +1,82 @@
1
+ # Sessions, secure storage, and widgets
2
+
3
+ ## Canonical session storage
4
+
5
+ The canonical `oidc-client-ts` user and authorization transaction state are
6
+ stored in separate native-secure namespaces. Values are never written to
7
+ `localStorage`.
8
+
9
+ - iOS stores generic-password items in Keychain with synchronization disabled.
10
+ - Android encrypts values with AES-GCM using a non-exportable Android Keystore
11
+ key and writes ciphertext to app-private no-backup storage.
12
+
13
+ The default iOS accessibility is `AfterFirstUnlockThisDeviceOnly`. Biometric
14
+ gating is not enabled because unattended foreground renewal must remain possible.
15
+
16
+ ## Renewal lifecycle
17
+
18
+ When `automaticSilentRenew` is enabled, `oidc-client-ts` schedules renewal while
19
+ the JavaScript runtime is active. The adapter also checks the current user when
20
+ the application resumes.
21
+
22
+ Native silent renewal requires a refresh token and never falls back to an iframe.
23
+ Concurrent renewal requests share one operation so a rotating refresh token is
24
+ not used twice. A terminal `invalid_grant` removes the local user; a temporary
25
+ network failure preserves it.
26
+
27
+ The operating system can suspend or terminate the process. The package therefore
28
+ does not guarantee exact background refresh timing.
29
+
30
+ ## Widget snapshot
31
+
32
+ Each successful canonical user write also updates a versioned `StoredSessionV1`
33
+ snapshot containing:
34
+
35
+ - issuer and client ID;
36
+ - access token and expiration;
37
+ - refresh token when issued;
38
+ - ID token when issued;
39
+ - token type and scope.
40
+
41
+ The refresh and ID tokens are intentionally retained so a future coordinated
42
+ native widget-refresh implementation does not require a storage-format migration.
43
+ This makes the widget extension part of the same credential trust boundary as
44
+ the host application.
45
+
46
+ The current plugin does **not** perform autonomous widget refresh. Widgets can use
47
+ a valid access token from the snapshot, but they must tolerate an expired, absent,
48
+ or temporarily stale snapshot. Independently rotating a refresh token in widget
49
+ code can invalidate the canonical application session and is not currently a
50
+ supported workflow.
51
+
52
+ The snapshot is an eventually consistent cache: the canonical OIDC user and the
53
+ snapshot are separate writes.
54
+
55
+ ## iOS widget access
56
+
57
+ Configure the same Keychain Sharing entitlement on the application and WidgetKit
58
+ extension. Both targets normally declare
59
+ `$(AppIdentifierPrefix)group.com.example.app`; the JavaScript option uses the
60
+ expanded `TEAMID.group.com.example.app` value.
61
+
62
+ ```swift
63
+ let vault = TokenVault(accessGroup: "TEAMID.group.com.example.app")
64
+ let session = try vault.loadSession(namespace: "primary")
65
+ ```
66
+
67
+ Configuring `keychainAccessGroup` places the plugin's canonical session,
68
+ transaction state, and widget snapshot in that shared access group. Do not grant
69
+ the entitlement to an extension you do not trust with the complete OIDC session.
70
+
71
+ ## Android widget access
72
+
73
+ An Android app widget in the same application package and UID can use the public
74
+ native vault:
75
+
76
+ ```java
77
+ TokenVault vault = new TokenVault(context);
78
+ StoredSessionV1 session = vault.loadSession("primary");
79
+ ```
80
+
81
+ Before using `session.accessToken`, compare `session.expiresAt` with the current
82
+ time and leave enough margin for the widget request to complete.
package/docs/TESTING.md CHANGED
@@ -1,42 +1,53 @@
1
1
  # Testing
2
2
 
3
- ## Local checks
3
+ ## Automated checks
4
4
 
5
- Run the TypeScript checks and package build:
5
+ Run TypeScript linting, unit tests, and the package build:
6
6
 
7
7
  ```sh
8
8
  npm run verify
9
9
  ```
10
10
 
11
- `verify` also checks that the TypeScript, Swift, and Java bridge constants still
12
- match `contracts/native-api.json`.
13
-
14
- Build the native libraries with:
11
+ Build and test the native libraries with:
15
12
 
16
13
  ```sh
17
14
  npm run verify:ios
18
15
  npm run verify:android
19
16
  ```
20
17
 
21
- CI runs Vitest, the iOS XCTest suite in a simulator, Android unit tests, native
22
- builds, Android lint, and `npm pack --dry-run`. The shared `StoredSessionV1`
23
- fixture is decoded or produced by all three platform implementations.
18
+ CI currently runs:
19
+
20
+ - TypeScript linting, Vitest, package builds, and `npm pack --dry-run`;
21
+ - iOS XCTest in an iOS 18.5 simulator;
22
+ - Android unit tests, assembly, and lint with SDK 36;
23
+ - packaged iOS and Android consumer builds with Capacitor 7 and 8;
24
+ - cross-platform decoding of the versioned `StoredSessionV1` fixture.
25
+
26
+ ## Current manual validation
24
27
 
25
- ## Physical-device coverage
28
+ Basic Amazon Cognito login has been tested in a packaged application on a
29
+ physical iOS device. The system authentication UI, callback, code exchange, and
30
+ resulting session work in that path.
26
31
 
27
- Before a stable release, install example applications on physical iOS and Android
28
- devices and verify:
32
+ This does not yet cover all iOS cancellation, logout, refresh, rotation, restart,
33
+ ephemeral-session, and error edge cases. Physical Android and the provider matrix
34
+ also remain incomplete.
35
+
36
+ ## Required physical-device coverage
37
+
38
+ Before a stable release, verify on physical iOS and Android devices:
29
39
 
30
40
  - system login and logout UI, provider-consent UI, cancellation, and callbacks;
31
41
  - Web Crypto availability in the packaged Capacitor WebView;
32
- - shared and ephemeral iOS browser sessions;
42
+ - shared and ephemeral browser sessions;
33
43
  - Keychain and Keystore persistence across app restarts;
34
- - session reads from iOS and Android widgets.
44
+ - refresh before expiry and refresh after resuming beyond expiry;
45
+ - reads from iOS and Android widgets.
35
46
 
36
47
  ## Provider integration coverage
37
48
 
38
- Run the following flows against at least two conforming providers, including a
39
- locally configurable provider:
49
+ The target matrix contains at least two conforming providers, including a locally
50
+ configurable provider, and covers:
40
51
 
41
52
  - discovery and explicit metadata;
42
53
  - login, code exchange, UserInfo, and logout;
@@ -45,3 +56,6 @@ locally configurable provider:
45
56
  - invalid state, nonce, callback, and ID-token claims;
46
57
  - a provider that omits refresh tokens;
47
58
  - a provider that rejects the configured Capacitor origin through CORS.
59
+
60
+ Provider configuration examples that have not been tested on physical devices are
61
+ labelled as guidance in [Provider configuration](PROVIDERS.md).
@@ -0,0 +1,67 @@
1
+ # Troubleshooting
2
+
3
+ ## Login fails before system UI opens
4
+
5
+ - Confirm `crypto.subtle` and `crypto.getRandomValues` exist in the packaged
6
+ Capacitor WebView.
7
+ - Confirm the authorization endpoint uses HTTPS.
8
+ - Confirm discovery succeeds, or provide complete static `metadata`.
9
+ - Inspect the error `code`; `BROWSER_UNAVAILABLE` and `UNSUPPORTED_RUNTIME`
10
+ identify adapter failures.
11
+
12
+ ## The provider reports a redirect mismatch
13
+
14
+ The authorization request's `redirect_uri` must exactly match a callback
15
+ registered for the provider client. Check scheme, host, port, path, case, and
16
+ trailing slashes. Wildcard callback hosts are commonly unsupported.
17
+
18
+ ## Android does not return to the app
19
+
20
+ - Keep `MainActivity` in `singleTask` launch mode.
21
+ - Put the callback intent filter inside the existing `MainActivity` declaration.
22
+ - Match the `<data android:scheme>` value to `redirect_uri`.
23
+ - If using HTTPS, verify the App Link and Digital Asset Links association.
24
+
25
+ See [Android setup](PLATFORM_SETUP.md#android).
26
+
27
+ ## iOS does not show the expected sheet or consent dialog
28
+
29
+ `ASWebAuthenticationSession` controls both presentation and the provider-consent
30
+ dialog. The operating system decides when consent is required and can remember a
31
+ previous decision. Verify that the Capacitor view controller has an active window
32
+ and that the callback scheme is registered in the target.
33
+
34
+ ## Token, UserInfo, refresh, or revocation fails with a network error
35
+
36
+ These requests use the WebView's normal `fetch`. Configure the provider endpoint
37
+ to allow the app's Capacitor origin through CORS. Static discovery metadata does
38
+ not remove CORS requirements from token, UserInfo, refresh, or revocation calls.
39
+
40
+ ## No refresh token is available
41
+
42
+ - Request the provider's offline-access scope when required.
43
+ - Enable the refresh-token grant for the public client.
44
+ - Check provider-specific consent and rotation settings.
45
+
46
+ When the current user is expired and has no refresh token, `getValidUser()`
47
+ removes the local user and returns `null`.
48
+
49
+ ## Manager creation fails while offline
50
+
51
+ The current alpha validates the restored session during
52
+ `CapacitorUserManager.create()`. If the stored access token needs renewal, a
53
+ temporary token-endpoint failure can reject creation. Initialize the manager from
54
+ a place that can surface a retry action. A future implementation should make
55
+ creation succeed offline and report renewal failure through `silentRenewError`.
56
+
57
+ ## Logout does not return to the app
58
+
59
+ Register the post-logout URI at the provider and in the native application. Some
60
+ providers use non-standard parameters. Amazon Cognito uses `logout_uri`; see
61
+ [Provider configuration](PROVIDERS.md#amazon-cognito).
62
+
63
+ ## `USER_CANCELLED` appears but Android UI remains visible
64
+
65
+ Android does not provide an API for forcibly closing an already-open Auth Tab or
66
+ Custom Tab. `cancel()` rejects the pending JavaScript operation and clears plugin
67
+ state; the user may still need to close the browser UI.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "capacitor-oidc",
3
- "version": "0.0.1-alpha.2",
3
+ "version": "0.0.2",
4
4
  "description": "A minimal Capacitor adapter for standards-based OpenID Connect authentication.",
5
5
  "main": "dist/plugin.cjs",
6
6
  "module": "dist/esm/index.js",
@@ -8,7 +8,8 @@
8
8
  "files": [
9
9
  "android/src/main/",
10
10
  "android/build.gradle",
11
- "contracts/",
11
+ "contracts/fixtures/stored-session-v1.json",
12
+ "contracts/stored-session-v1.schema.json",
12
13
  "dist/",
13
14
  "docs/",
14
15
  "ios/Sources",
@@ -19,8 +20,7 @@
19
20
  ],
20
21
  "license": "Apache-2.0",
21
22
  "author": {
22
- "name": "Jojo Pirker",
23
- "email": "j.pirker@gmail.com"
23
+ "name": "Jojo Pirker"
24
24
  },
25
25
  "repository": {
26
26
  "type": "git",