capacitor-oidc 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/SECURITY.md +23 -27
- package/docs/PROVIDERS.md +23 -29
- package/docs/README.md +1 -1
- package/docs/adr/index.md +6 -0
- package/docs/frameworks/ANGULAR.md +129 -0
- package/docs/frameworks/REACT.md +134 -0
- package/docs/frameworks/VUE.md +118 -0
- package/package.json +6 -1
package/README.md
CHANGED
|
@@ -104,7 +104,7 @@ callback route, call `signinCallback()`; on the web logout callback route, call
|
|
|
104
104
|
`web` or `native`, then the matching `ios` or `android` override.
|
|
105
105
|
|
|
106
106
|
A runnable Keycloak-backed iOS application and its UI test live in
|
|
107
|
-
[`example`](example).
|
|
107
|
+
[`example`](example/).
|
|
108
108
|
|
|
109
109
|
## Documentation
|
|
110
110
|
|
|
@@ -127,7 +127,7 @@ npm run verify:android
|
|
|
127
127
|
|
|
128
128
|
Architecture decisions and contributor constraints are documented in
|
|
129
129
|
[ARCHITECTURE.md](ARCHITECTURE.md), [REQUIREMENTS.md](REQUIREMENTS.md), and
|
|
130
|
-
[docs/adr](docs/adr).
|
|
130
|
+
[docs/adr](docs/adr/).
|
|
131
131
|
|
|
132
132
|
## License
|
|
133
133
|
|
package/SECURITY.md
CHANGED
|
@@ -12,33 +12,6 @@ with PKCE and cannot contain a client secret. Native authorization and provider
|
|
|
12
12
|
logout run in system authentication UI, never an embedded WebView; web uses
|
|
13
13
|
normal browser redirect or popup navigation.
|
|
14
14
|
|
|
15
|
-
## ID-token validation in `oidc-client-ts` 3.5.0
|
|
16
|
-
|
|
17
|
-
The pinned `oidc-client-ts` 3.5.0 decodes ID-token claims and validates `sub`,
|
|
18
|
-
`nonce`, and selected refresh-token continuity claims. It does not independently
|
|
19
|
-
compare the decoded `iss`, `aud`, and `exp` claims with the configured client and
|
|
20
|
-
current time. This behavior is visible in the
|
|
21
|
-
[v3.5.0 ResponseValidator](https://github.com/authts/oidc-client-ts/blob/v3.5.0/src/ResponseValidator.ts)
|
|
22
|
-
and is the subject of the open upstream report
|
|
23
|
-
[authts/oidc-client-ts#2475](https://github.com/authts/oidc-client-ts/issues/2475).
|
|
24
|
-
|
|
25
|
-
The practical exposure is narrower than an implicit-flow token parser: this
|
|
26
|
-
package uses Authorization Code Flow only, and the token response comes from the
|
|
27
|
-
configured token endpoint over TLS after state, nonce, and PKCE processing. The
|
|
28
|
-
upstream project has not yet classified or resolved the report.
|
|
29
|
-
|
|
30
|
-
This is a standards-conformance and threat-model consideration, not a categorical
|
|
31
|
-
claim that every application using `oidc-client-ts` is unsafe. Consumers should
|
|
32
|
-
evaluate it against their provider, reliance on ID-token claims, and assurance
|
|
33
|
-
requirements. Resource servers must always validate access tokens independently;
|
|
34
|
-
an application must not use unverified client-side profile claims as its API
|
|
35
|
-
authorization boundary.
|
|
36
|
-
|
|
37
|
-
The package will follow the upstream resolution and cover the expected behavior
|
|
38
|
-
in provider integration tests before a stable v1 decision. It will not add a
|
|
39
|
-
package-local JWT or cryptographic-validation layer, because duplicating protocol
|
|
40
|
-
security code would expand the attack surface and create a second OIDC engine.
|
|
41
|
-
|
|
42
15
|
## Secure-storage boundary
|
|
43
16
|
|
|
44
17
|
OIDC transactions and sessions are stored through iOS Keychain or an Android
|
|
@@ -59,3 +32,26 @@ absent. Their behavior must be verified in packaged applications on supported
|
|
|
59
32
|
physical devices.
|
|
60
33
|
|
|
61
34
|
See [Testing](docs/TESTING.md) for current platform and provider coverage.
|
|
35
|
+
|
|
36
|
+
## Known issues
|
|
37
|
+
|
|
38
|
+
### ID-token claim validation in `oidc-client-ts` 3.5.0
|
|
39
|
+
|
|
40
|
+
The pinned `oidc-client-ts` 3.5.0 decodes ID-token claims and validates `sub`,
|
|
41
|
+
`nonce`, and selected refresh-token continuity claims. It does not independently
|
|
42
|
+
compare the decoded `iss`, `aud`, and `exp` claims with the configured client and
|
|
43
|
+
current time. This behavior is visible in the
|
|
44
|
+
[v3.5.0 ResponseValidator](https://github.com/authts/oidc-client-ts/blob/v3.5.0/src/ResponseValidator.ts)
|
|
45
|
+
and is the subject of the unresolved upstream report
|
|
46
|
+
[authts/oidc-client-ts#2475](https://github.com/authts/oidc-client-ts/issues/2475).
|
|
47
|
+
|
|
48
|
+
This package uses Authorization Code Flow, so the token response comes from the
|
|
49
|
+
configured token endpoint over TLS after state, nonce, and PKCE processing.
|
|
50
|
+
Applications that rely on `iss`, `aud`, or `exp` claims should still evaluate
|
|
51
|
+
the upstream gap against their assurance requirements. Resource servers must
|
|
52
|
+
validate access tokens independently, and client-side ID-token claims must not
|
|
53
|
+
be an API authorization boundary.
|
|
54
|
+
|
|
55
|
+
The package will follow the upstream resolution and cover the expected behavior
|
|
56
|
+
in provider integration tests before a stable v1 decision. It will not add a
|
|
57
|
+
package-local JWT validation layer that would duplicate protocol security code.
|
package/docs/PROVIDERS.md
CHANGED
|
@@ -1,33 +1,27 @@
|
|
|
1
1
|
# Provider configuration
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
##
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
The
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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. |
|
|
3
|
+
The recipes below cover the settings that differ between providers.
|
|
4
|
+
`capacitor-oidc` does not contain provider-specific protocol code; it passes the
|
|
5
|
+
configured OpenID Connect settings to `oidc-client-ts`.
|
|
6
|
+
|
|
7
|
+
## Requirements
|
|
8
|
+
|
|
9
|
+
Use a public client that supports Authorization Code Flow with `S256` PKCE.
|
|
10
|
+
Register every web and native redirect URI and post-logout redirect URI exactly,
|
|
11
|
+
and configure the provider application without a client secret. A secret cannot
|
|
12
|
+
be kept in a Capacitor app.
|
|
13
|
+
|
|
14
|
+
If the app refreshes or revokes tokens, or loads UserInfo from the Capacitor
|
|
15
|
+
runtime, the provider must allow the configured Capacitor origin to call those
|
|
16
|
+
endpoints. Request `offline_access`, or the provider's equivalent, when the app
|
|
17
|
+
needs refresh tokens. Use HTTPS outside local test environments.
|
|
18
|
+
|
|
19
|
+
## Test status
|
|
20
|
+
|
|
21
|
+
The basic Amazon Cognito sign-in flow has been tested on a physical iOS device.
|
|
22
|
+
The Auth0, Keycloak, Okta, and Microsoft Entra ID sections document expected
|
|
23
|
+
configuration, but those recipes are not yet covered by the package's provider
|
|
24
|
+
integration tests.
|
|
31
25
|
|
|
32
26
|
## Amazon Cognito
|
|
33
27
|
|
|
@@ -188,7 +182,7 @@ and [redirect URI restrictions](https://learn.microsoft.com/en-us/entra/identity
|
|
|
188
182
|
|
|
189
183
|
## Other providers
|
|
190
184
|
|
|
191
|
-
Start with the
|
|
185
|
+
Start with the requirements above and the provider's OpenID Connect discovery
|
|
192
186
|
document. If discovery does not describe a usable native flow, pass explicit
|
|
193
187
|
`metadata` through the upstream `UserManagerSettings` rather than adding
|
|
194
188
|
provider-specific code to this package.
|
package/docs/README.md
CHANGED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Architecture decisions
|
|
2
|
+
|
|
3
|
+
- [Use `oidc-client-ts`](0001-use-oidc-client-ts.md)
|
|
4
|
+
- [Keep the native boundary small](0002-keep-the-native-boundary-small.md)
|
|
5
|
+
- [Share session storage with widgets](0003-share-session-storage-with-widgets.md)
|
|
6
|
+
- [Use one manager across platforms](0004-use-one-manager-across-platforms.md)
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# Angular integration
|
|
2
|
+
|
|
3
|
+
The [Angular example](/examples/angular/) keeps one OIDC manager in a root
|
|
4
|
+
service. The service completes browser callbacks, restores the current user,
|
|
5
|
+
and exposes signals for templates.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npm install capacitor-oidc @capacitor/app
|
|
11
|
+
npx cap sync
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Configure the provider
|
|
15
|
+
|
|
16
|
+
Keep deploy-specific values in an Angular environment file:
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
// src/environments/environment.ts
|
|
20
|
+
export const environment = {
|
|
21
|
+
authority: 'https://identity.example.com',
|
|
22
|
+
clientId: 'public-app',
|
|
23
|
+
};
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Create a root service
|
|
27
|
+
|
|
28
|
+
`providedIn: 'root'` gives the application one manager, independent of route
|
|
29
|
+
and component lifetimes:
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
@Injectable({ providedIn: 'root' })
|
|
33
|
+
export class OidcService {
|
|
34
|
+
readonly user = signal<User | null>(null);
|
|
35
|
+
|
|
36
|
+
private readonly manager = CapacitorUserManager.create({
|
|
37
|
+
common: {
|
|
38
|
+
authority: environment.authority,
|
|
39
|
+
client_id: environment.clientId,
|
|
40
|
+
scope: 'openid profile offline_access',
|
|
41
|
+
automaticSilentRenew: false,
|
|
42
|
+
},
|
|
43
|
+
web: {
|
|
44
|
+
settings: {
|
|
45
|
+
redirect_uri: `${window.location.origin}/callback`,
|
|
46
|
+
post_logout_redirect_uri: `${window.location.origin}/logout-callback`,
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
native: {
|
|
50
|
+
settings: {
|
|
51
|
+
redirect_uri: 'capacitor-oidc-example:/callback',
|
|
52
|
+
post_logout_redirect_uri: 'capacitor-oidc-example:/logout-callback',
|
|
53
|
+
},
|
|
54
|
+
options: { storageNamespace: 'angular-example' },
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The runnable example keeps automatic renewal off so the bundled realm's
|
|
61
|
+
30-second test tokens can be renewed with the example's button. For a normal
|
|
62
|
+
provider, enable automatic renewal and keep its expiry-notification threshold
|
|
63
|
+
below the provider's access-token lifetime.
|
|
64
|
+
|
|
65
|
+
## Initialize from the root component
|
|
66
|
+
|
|
67
|
+
The service handles browser callbacks before exposing the restored user:
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
async initialize() {
|
|
71
|
+
const auth = await this.manager;
|
|
72
|
+
|
|
73
|
+
auth.events.addUserLoaded((user) => this.user.set(user));
|
|
74
|
+
auth.events.addUserUnloaded(() => this.user.set(null));
|
|
75
|
+
|
|
76
|
+
if (window.location.pathname === '/callback') {
|
|
77
|
+
await auth.signinCallback();
|
|
78
|
+
window.history.replaceState({}, '', '/');
|
|
79
|
+
} else if (window.location.pathname === '/logout-callback') {
|
|
80
|
+
await auth.signoutCallback();
|
|
81
|
+
window.history.replaceState({}, '', '/');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
this.user.set(await auth.getUser());
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Call it once from the root component:
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
export class AppComponent implements OnInit {
|
|
92
|
+
readonly oidc = inject(OidcService);
|
|
93
|
+
|
|
94
|
+
ngOnInit() {
|
|
95
|
+
void this.oidc.initialize();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Native callbacks finish inside the plugin and do not need Angular Router
|
|
101
|
+
routes.
|
|
102
|
+
|
|
103
|
+
## Bind actions
|
|
104
|
+
|
|
105
|
+
The root service can expose `signin()`, `getValidUser(60)`, and `signout()` as
|
|
106
|
+
methods. Components read the current `user` signal and do not hold their own
|
|
107
|
+
manager.
|
|
108
|
+
|
|
109
|
+
Call `dispose()` only when the Angular application is shutting down.
|
|
110
|
+
|
|
111
|
+
## Run the example
|
|
112
|
+
|
|
113
|
+
```sh
|
|
114
|
+
npm ci
|
|
115
|
+
npm run build
|
|
116
|
+
npm run e2e:keycloak:up
|
|
117
|
+
npm --prefix examples/angular install
|
|
118
|
+
npm --prefix examples/angular run dev
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Sign in with the disposable `demo` / `demo` account. Stop the local realm with
|
|
122
|
+
`npm run e2e:keycloak:down` when finished.
|
|
123
|
+
|
|
124
|
+
This local realm workflow is for the browser example. Android resolves
|
|
125
|
+
`localhost` inside the device or emulator, and native platforms should not use
|
|
126
|
+
the example's cleartext HTTP authority. Before building for iOS or Android,
|
|
127
|
+
replace `environment.authority` with an HTTPS authority reachable from that
|
|
128
|
+
device and register the configured native callback scheme at the provider. See
|
|
129
|
+
[iOS and Android setup](../PLATFORM_SETUP.md).
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# React integration
|
|
2
|
+
|
|
3
|
+
The [React example](/examples/react/) creates its OIDC manager outside the
|
|
4
|
+
component tree, restores the user when the application mounts, and keeps React
|
|
5
|
+
state aligned with the manager's user events.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npm install capacitor-oidc @capacitor/app
|
|
11
|
+
npx cap sync
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Create the manager outside React
|
|
15
|
+
|
|
16
|
+
A module-level promise prevents component renders from constructing multiple
|
|
17
|
+
managers:
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
// src/auth.ts
|
|
21
|
+
import { CapacitorUserManager } from 'capacitor-oidc';
|
|
22
|
+
|
|
23
|
+
const manager = CapacitorUserManager.create({
|
|
24
|
+
common: {
|
|
25
|
+
authority: import.meta.env.VITE_OIDC_AUTHORITY,
|
|
26
|
+
client_id: import.meta.env.VITE_OIDC_CLIENT_ID,
|
|
27
|
+
scope: 'openid profile offline_access',
|
|
28
|
+
automaticSilentRenew: false,
|
|
29
|
+
},
|
|
30
|
+
web: {
|
|
31
|
+
settings: {
|
|
32
|
+
redirect_uri: `${window.location.origin}/callback`,
|
|
33
|
+
post_logout_redirect_uri: `${window.location.origin}/logout-callback`,
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
native: {
|
|
37
|
+
settings: {
|
|
38
|
+
redirect_uri: 'capacitor-oidc-example:/callback',
|
|
39
|
+
post_logout_redirect_uri: 'capacitor-oidc-example:/logout-callback',
|
|
40
|
+
},
|
|
41
|
+
options: { storageNamespace: 'react-example' },
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
export function getUserManager() {
|
|
46
|
+
return manager;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
let callback: Promise<void> | undefined;
|
|
50
|
+
|
|
51
|
+
export function completeWebCallback(auth: CapacitorUserManager) {
|
|
52
|
+
callback ??= (async () => {
|
|
53
|
+
if (window.location.pathname === '/callback') {
|
|
54
|
+
await auth.signinCallback();
|
|
55
|
+
window.history.replaceState({}, '', '/');
|
|
56
|
+
} else if (window.location.pathname === '/logout-callback') {
|
|
57
|
+
await auth.signoutCallback();
|
|
58
|
+
window.history.replaceState({}, '', '/');
|
|
59
|
+
}
|
|
60
|
+
})();
|
|
61
|
+
|
|
62
|
+
return callback;
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The runnable example supplies local Keycloak defaults and keeps automatic
|
|
67
|
+
renewal off so its 30-second test tokens can be renewed with the example's
|
|
68
|
+
button. For a normal provider, enable automatic renewal and keep its
|
|
69
|
+
expiry-notification threshold below the provider's access-token lifetime. Set
|
|
70
|
+
the two Vite environment variables for your provider.
|
|
71
|
+
|
|
72
|
+
## Initialize from the application root
|
|
73
|
+
|
|
74
|
+
Complete browser callbacks, subscribe to user events, and restore the stored
|
|
75
|
+
user from the root component:
|
|
76
|
+
|
|
77
|
+
```tsx
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
let active = true;
|
|
80
|
+
let auth: CapacitorUserManager | undefined;
|
|
81
|
+
const userLoaded = (user: User) => active && setUser(user);
|
|
82
|
+
const userUnloaded = () => active && setUser(null);
|
|
83
|
+
|
|
84
|
+
void getUserManager().then(async (manager) => {
|
|
85
|
+
if (!active) return;
|
|
86
|
+
auth = manager;
|
|
87
|
+
manager.events.addUserLoaded(userLoaded);
|
|
88
|
+
manager.events.addUserUnloaded(userUnloaded);
|
|
89
|
+
await completeWebCallback(manager);
|
|
90
|
+
const storedUser = await manager.getUser();
|
|
91
|
+
if (active) setUser(storedUser);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
return () => {
|
|
95
|
+
active = false;
|
|
96
|
+
auth?.events.removeUserLoaded(userLoaded);
|
|
97
|
+
auth?.events.removeUserUnloaded(userUnloaded);
|
|
98
|
+
};
|
|
99
|
+
}, []);
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Native callbacks complete inside the plugin and do not require React Router
|
|
103
|
+
routes.
|
|
104
|
+
|
|
105
|
+
## Bind actions
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
await auth.signin();
|
|
109
|
+
setUser(await auth.getValidUser(60));
|
|
110
|
+
await auth.signout();
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Retain the manager when React routes change. Call `dispose()` only when the
|
|
114
|
+
whole application is shutting down.
|
|
115
|
+
|
|
116
|
+
## Run the example
|
|
117
|
+
|
|
118
|
+
```sh
|
|
119
|
+
npm ci
|
|
120
|
+
npm run build
|
|
121
|
+
npm run e2e:keycloak:up
|
|
122
|
+
npm --prefix examples/react install
|
|
123
|
+
npm --prefix examples/react run dev
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Sign in with the disposable `demo` / `demo` account. Stop the local realm with
|
|
127
|
+
`npm run e2e:keycloak:down` when finished.
|
|
128
|
+
|
|
129
|
+
This local realm workflow is for the browser example. Android resolves
|
|
130
|
+
`localhost` inside the device or emulator, and native platforms should not use
|
|
131
|
+
the example's cleartext HTTP authority. Before building for iOS or Android, set
|
|
132
|
+
`VITE_OIDC_AUTHORITY` to an HTTPS authority reachable from that device and
|
|
133
|
+
register the configured native callback scheme at the provider. See
|
|
134
|
+
[iOS and Android setup](../PLATFORM_SETUP.md).
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# Vue integration
|
|
2
|
+
|
|
3
|
+
The [Vue example](/examples/vue/) is a small Capacitor application with one
|
|
4
|
+
OIDC manager for the application lifetime. It restores the stored user when
|
|
5
|
+
Vue mounts, completes browser callbacks, and exposes sign-in, renewal, and
|
|
6
|
+
sign-out actions.
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
npm install capacitor-oidc @capacitor/app
|
|
12
|
+
npx cap sync
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Create the manager once
|
|
16
|
+
|
|
17
|
+
Keep manager creation outside Vue components so route changes cannot create a
|
|
18
|
+
second manager:
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
// src/auth.ts
|
|
22
|
+
import { CapacitorUserManager } from 'capacitor-oidc';
|
|
23
|
+
|
|
24
|
+
const manager = CapacitorUserManager.create({
|
|
25
|
+
common: {
|
|
26
|
+
authority: import.meta.env.VITE_OIDC_AUTHORITY,
|
|
27
|
+
client_id: import.meta.env.VITE_OIDC_CLIENT_ID,
|
|
28
|
+
scope: 'openid profile offline_access',
|
|
29
|
+
automaticSilentRenew: false,
|
|
30
|
+
},
|
|
31
|
+
web: {
|
|
32
|
+
settings: {
|
|
33
|
+
redirect_uri: `${window.location.origin}/callback`,
|
|
34
|
+
post_logout_redirect_uri: `${window.location.origin}/logout-callback`,
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
native: {
|
|
38
|
+
settings: {
|
|
39
|
+
redirect_uri: 'capacitor-oidc-example:/callback',
|
|
40
|
+
post_logout_redirect_uri: 'capacitor-oidc-example:/logout-callback',
|
|
41
|
+
},
|
|
42
|
+
options: { storageNamespace: 'vue-example' },
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
export function getUserManager() {
|
|
47
|
+
return manager;
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The runnable example supplies local Keycloak defaults as a convenience and
|
|
52
|
+
keeps automatic renewal off so its 30-second test tokens can be renewed with
|
|
53
|
+
the example's button. For a normal provider, enable automatic renewal and keep
|
|
54
|
+
its expiry-notification threshold below the provider's access-token lifetime.
|
|
55
|
+
Use environment variables for your provider in an application.
|
|
56
|
+
|
|
57
|
+
## Restore state and handle callbacks
|
|
58
|
+
|
|
59
|
+
Initialize authentication from the root component. Browser callback routes
|
|
60
|
+
must be handled before rendering the restored user:
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
const auth = await getUserManager();
|
|
64
|
+
|
|
65
|
+
if (window.location.pathname === '/callback') {
|
|
66
|
+
await auth.signinCallback();
|
|
67
|
+
window.history.replaceState({}, '', '/');
|
|
68
|
+
} else if (window.location.pathname === '/logout-callback') {
|
|
69
|
+
await auth.signoutCallback();
|
|
70
|
+
window.history.replaceState({}, '', '/');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
user.value = await auth.getUser();
|
|
74
|
+
|
|
75
|
+
auth.events.addUserLoaded((loadedUser) => {
|
|
76
|
+
user.value = loadedUser;
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
auth.events.addUserUnloaded(() => {
|
|
80
|
+
user.value = null;
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Native callbacks are completed by the plugin and do not need Vue Router
|
|
85
|
+
routes.
|
|
86
|
+
|
|
87
|
+
## Bind actions
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
await auth.signin();
|
|
91
|
+
user.value = await auth.getValidUser(60);
|
|
92
|
+
await auth.signout();
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Call `dispose()` only when the application is shutting down, not whenever a
|
|
96
|
+
route component unmounts.
|
|
97
|
+
|
|
98
|
+
## Run the example
|
|
99
|
+
|
|
100
|
+
Start the repository's local Keycloak realm, then start the Vue app:
|
|
101
|
+
|
|
102
|
+
```sh
|
|
103
|
+
npm ci
|
|
104
|
+
npm run build
|
|
105
|
+
npm run e2e:keycloak:up
|
|
106
|
+
npm --prefix examples/vue install
|
|
107
|
+
npm --prefix examples/vue run dev
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Sign in with the disposable `demo` / `demo` account. Stop the local realm with
|
|
111
|
+
`npm run e2e:keycloak:down` when finished.
|
|
112
|
+
|
|
113
|
+
This local realm workflow is for the browser example. Android resolves
|
|
114
|
+
`localhost` inside the device or emulator, and native platforms should not use
|
|
115
|
+
the example's cleartext HTTP authority. Before building for iOS or Android, set
|
|
116
|
+
`VITE_OIDC_AUTHORITY` to an HTTPS authority reachable from that device and
|
|
117
|
+
register the configured native callback scheme at the provider. See
|
|
118
|
+
[iOS and Android setup](../PLATFORM_SETUP.md).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "capacitor-oidc",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "OAuth 2.0 and OpenID Connect authentication for Capacitor web, iOS, and Android, powered by oidc-client-ts.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"capacitor",
|
|
@@ -49,6 +49,9 @@
|
|
|
49
49
|
"build": "npm run clean && tsc && rollup -c rollup.config.mjs",
|
|
50
50
|
"check:package": "node -e \"import('./dist/esm/index.js')\"",
|
|
51
51
|
"clean": "rimraf dist",
|
|
52
|
+
"docs:build": "vitepress build . && cp LICENSE .vitepress/dist/LICENSE",
|
|
53
|
+
"docs:dev": "vitepress dev .",
|
|
54
|
+
"docs:preview": "vitepress preview .",
|
|
52
55
|
"e2e:keycloak:down": "docker compose -f test/e2e/keycloak/compose.yml down",
|
|
53
56
|
"e2e:keycloak:up": "test/e2e/keycloak/create-certificate.sh test/e2e/keycloak/.certificates && docker compose -f test/e2e/keycloak/compose.yml up -d",
|
|
54
57
|
"example:build": "npm --prefix example run build",
|
|
@@ -79,6 +82,8 @@
|
|
|
79
82
|
"rimraf": "6.1.0",
|
|
80
83
|
"rollup": "4.62.5",
|
|
81
84
|
"typescript": "5.9.3",
|
|
85
|
+
"vite": "7.3.6",
|
|
86
|
+
"vitepress": "2.0.0-alpha.19",
|
|
82
87
|
"vitest": "3.2.7"
|
|
83
88
|
},
|
|
84
89
|
"prettier": "@ionic/prettier-config",
|