@okta/spa-platform 0.6.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +204 -0
- package/claude.md +562 -0
- package/dist/esm/Credential/Credential.js.map +1 -1
- package/dist/esm/Credential/CredentialCoordinator.js +25 -22
- package/dist/esm/Credential/CredentialCoordinator.js.map +1 -1
- package/dist/esm/Credential/TokenStorage.js +19 -3
- package/dist/esm/Credential/TokenStorage.js.map +1 -1
- package/dist/esm/FetchClient/index.js.map +1 -1
- package/dist/esm/core.js +25 -0
- package/dist/esm/core.js.map +1 -0
- package/dist/esm/flows/AuthorizationCodeFlow.js.map +1 -1
- package/dist/esm/flows/SessionLogoutFlow.js.map +1 -1
- package/dist/esm/flows/TransactionStorage.js.map +1 -1
- package/dist/esm/flows.js +30 -0
- package/dist/esm/flows.js.map +1 -0
- package/dist/esm/index.js +4 -13
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/orchestrators/AuthorizationCodeFlowOrchestrator.js +4 -0
- package/dist/esm/orchestrators/AuthorizationCodeFlowOrchestrator.js.map +1 -1
- package/dist/esm/orchestrators/HostOrchestrator/Host.js +9 -1
- package/dist/esm/orchestrators/HostOrchestrator/Host.js.map +1 -1
- package/dist/esm/orchestrators/HostOrchestrator/OrchestrationBridge.js.map +1 -1
- package/dist/esm/orchestrators/HostOrchestrator/SubApp.js +8 -2
- package/dist/esm/orchestrators/HostOrchestrator/SubApp.js.map +1 -1
- package/dist/esm/orchestrators/HostOrchestrator/index.js +11 -6
- package/dist/esm/orchestrators/HostOrchestrator/index.js.map +1 -1
- package/dist/esm/platform/OAuth2Client.js +4 -7
- package/dist/esm/platform/OAuth2Client.js.map +1 -1
- package/dist/esm/platform/defaults.js.map +1 -1
- package/dist/esm/platform/index.js.map +1 -1
- package/dist/esm/utils/IndexedDBStore.js +27 -18
- package/dist/esm/utils/IndexedDBStore.js.map +1 -1
- package/dist/esm/utils/SynchronizedResult.js +53 -60
- package/dist/esm/utils/SynchronizedResult.js.map +1 -1
- package/dist/esm/utils/isModernBrowser.js.map +1 -1
- package/dist/types/Credential/Credential.d.ts +8 -2
- package/dist/types/Credential/TokenStorage.d.ts +25 -1
- package/dist/types/FetchClient/index.d.ts +6 -0
- package/dist/types/core.d.ts +19 -0
- package/dist/types/flows/AuthorizationCodeFlow.d.ts +63 -13
- package/dist/types/flows/SessionLogoutFlow.d.ts +24 -0
- package/dist/types/flows/TransactionStorage.d.ts +7 -0
- package/dist/types/flows/index.d.ts +15 -2
- package/dist/types/flows.d.ts +9 -0
- package/dist/types/index.d.ts +1 -14
- package/dist/types/orchestrators/AuthorizationCodeFlowOrchestrator.d.ts +40 -6
- package/dist/types/orchestrators/HostOrchestrator/Host.d.ts +15 -0
- package/dist/types/orchestrators/HostOrchestrator/OrchestrationBridge.d.ts +4 -0
- package/dist/types/orchestrators/HostOrchestrator/SubApp.d.ts +13 -2
- package/dist/types/orchestrators/HostOrchestrator/index.d.ts +50 -16
- package/dist/types/orchestrators/index.d.ts +4 -1
- package/dist/types/platform/OAuth2Client.d.ts +9 -3
- package/dist/types/platform/defaults.d.ts +8 -0
- package/dist/types/platform/index.d.ts +6 -0
- package/dist/types/utils/IndexedDBStore.d.ts +1 -0
- package/dist/types/utils/SynchronizedResult.d.ts +1 -8
- package/dist/types/utils/isModernBrowser.d.ts +2 -1
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
---
|
|
2
|
+
outline: [2, 3]
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# @okta/spa-platform
|
|
6
|
+
|
|
7
|
+
Platform library for browser environments for the Okta Client JavaScript ecosystem
|
|
8
|
+
|
|
9
|
+
## Requirements
|
|
10
|
+
|
|
11
|
+
This library is written for modern JavaScript environments, targeting MDN's [Baseline 2022](https://developer.mozilla.org/en-US/docs/Glossary/Baseline/Compatibility) feature sets. Most notably utilizing the following APIs:
|
|
12
|
+
|
|
13
|
+
* [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)
|
|
14
|
+
* [WebCrypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API)
|
|
15
|
+
* [Web Locks API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Locks_API)
|
|
16
|
+
* [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API)
|
|
17
|
+
* [Broadcast Channel API](https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API)
|
|
18
|
+
|
|
19
|
+
> [!NOTE]
|
|
20
|
+
> This library does not support Internet Explorer out-of-the-box. Polyfills will be required.
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
yarn add @okta/auth-foundation @okta/spa-platform
|
|
26
|
+
# optionally include @okta/oauth2-flows
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Entry Points
|
|
30
|
+
|
|
31
|
+
(Recommended) Importing `@okta/spa-platform` has the following side effects:
|
|
32
|
+
|
|
33
|
+
- Registers the `@okta/spa-platform` Platform defaults
|
|
34
|
+
- Replaces `CredentialCoordinator.tokenStorage` with `BrowserTokenStorage`
|
|
35
|
+
|
|
36
|
+
All core exports are available via `@okta/spa-platform/core` to avoid the side effects, if required. Although, the `core` export is unlikely to result in desired functionality out-of-the-box.
|
|
37
|
+
|
|
38
|
+
To perform OAuth2 flows (like Authorization Code flow) a peer dependency of `@okta/oauth2-flows` is required. All features dependent on `@okta/oauth2-flows` are exported from `@okta/spa-platform/flows`, so `@okta/oauth2-flows` can be listed as a optional peer dependency
|
|
39
|
+
|
|
40
|
+
> All exports from `@okta/auth-foundation` and `@okta/oauth2-flows` are re-exported from `@okta/spa-platform`. Always import from `@okta/spa-platform` or a subpath
|
|
41
|
+
|
|
42
|
+
## Usage
|
|
43
|
+
|
|
44
|
+
### `isModernBrowser`
|
|
45
|
+
|
|
46
|
+
This library requires modern JavaScript APIs (see [requirements](#requirements)). This utility method returns `true` when the required APIs are available.
|
|
47
|
+
|
|
48
|
+
## Platform
|
|
49
|
+
|
|
50
|
+
### `BrowserTokenStorage`
|
|
51
|
+
|
|
52
|
+
Default implementation of `TokenStorage` backend by [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage)
|
|
53
|
+
|
|
54
|
+
By default, all tokens will be encrypted (via `AES-GCM`) before being written to storage. `Token.Metadata` is stored separately an unencrypted.
|
|
55
|
+
This enables storage queries (via `Credential.find`) to search on claims without decrypting tokens
|
|
56
|
+
|
|
57
|
+
#### Configurations
|
|
58
|
+
|
|
59
|
+
| Property | Description | Default |
|
|
60
|
+
| ------ | ------ | ------ |
|
|
61
|
+
| `tokenPrefix` | A storage key prefix to identify entries by. | `'oauth-token'` |
|
|
62
|
+
| `encryptAtRest` | When `true`, tokens will be encrypted (via `AES-GCM`) before being written to storage. | `true` |
|
|
63
|
+
| `includeClaims` | When `true`, includes `idToken` claims in stored `Token.Metadata`. This includes `claims` within `Credential.find` queries | `true` |
|
|
64
|
+
| `encryptionKeyStore` | A [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API)-backed store for managing storage encryption key(s) | `new IndexedDBStore<CryptoKey>('StorageKeys')` |
|
|
65
|
+
| `encryptionKeyName` | Key name of the storage encryption key with the `encryptionKeyStore` | `'EncryptionKey'` |
|
|
66
|
+
|
|
67
|
+
#### Customizing
|
|
68
|
+
|
|
69
|
+
> [!Tip]
|
|
70
|
+
> Updating storage configurations (or instances altogether) should happen at application bootstrap time. Making dynamic changes within an application's lifecycle may have unpredicatable results
|
|
71
|
+
|
|
72
|
+
Configuration properties can be updated directly
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
import { Credential } from '@okta/spa-platform';
|
|
76
|
+
|
|
77
|
+
// Reference to default `BrowserTokenStorage` instance
|
|
78
|
+
Credential.coordinator.tokenStorage;
|
|
79
|
+
|
|
80
|
+
// Updates configuration property
|
|
81
|
+
Credential.coordinator.tokenStorage.includeClaims = false;
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Or the storage class can be extended
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
import { Credential, BrowserTokenStorage } from '@okta/spa-platform';
|
|
88
|
+
|
|
89
|
+
class MyTokenStorage extends BrowserTokenStorage {
|
|
90
|
+
includeClaims = false;
|
|
91
|
+
|
|
92
|
+
protected async handleReadError (error: unknown, id: string) {
|
|
93
|
+
throw new TypeError('Something went wrong');
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
Credential.coordinator.tokenStorage = new MyTokenStorage();
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Authorization Code Flow
|
|
101
|
+
|
|
102
|
+
Browser-specific ultilies methods for performing [Authorization Code Flow](/docs/references/authorization_code_flow) in a browser environment.
|
|
103
|
+
|
|
104
|
+
### `PerformRedirect` [:book:](/api/spa-platform/flows/AuthorizationCodeFlow/#performredirect)
|
|
105
|
+
|
|
106
|
+
> **Recommended Appoarch**
|
|
107
|
+
|
|
108
|
+
Performs a browser full-page redirect to the Authorization Server `/authorize` endpoint.
|
|
109
|
+
Once authentication is successful, the user will be redirected back to the provided `redirectUri`
|
|
110
|
+
|
|
111
|
+
> [!Tip]
|
|
112
|
+
> This requires the SPA handles the redirect at the provided `redirectUri` path via `.resume()`
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
import { OAuth2Client, Credential } from '@okta/spa-platform';
|
|
116
|
+
import { AuthorizationCodeFlow } from '@okta/spa-platform/flows';
|
|
117
|
+
|
|
118
|
+
const client = new OAuth2Client({ ... });
|
|
119
|
+
|
|
120
|
+
const flow = new AuthorizationCodeFlow(client, {
|
|
121
|
+
redirectUri: REDIRECT_URI
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
export async function performSignIn () {
|
|
125
|
+
// NOTE: the resulting `Promise` from `PerformRedirect` never fulfills,
|
|
126
|
+
// so execution is blocking until the full-page direct occurs
|
|
127
|
+
return AuthorizationCodeFlow.PerformRedirect(flow);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// **MUST** be invoked at the `redirectUri` path to handle the redirect
|
|
131
|
+
// from the authorization server
|
|
132
|
+
export async function handleAuthorizationCodeFlowResponse () {
|
|
133
|
+
const { token } = await flow.resume(window.location.href);
|
|
134
|
+
await Credential.store(token);
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### `PerformSilently` [:book:](/api/spa-platform/flows/AuthorizationCodeFlow/#performsilently)
|
|
139
|
+
|
|
140
|
+
Fulfills the `/authorize` request within a hidden iframe and therefore does *not* require a redirect. Does not prompt the user for credentials, however requires an existing IDP session; persumably the user was already prompted to establish this session. IDP sessions are (usually) cookie-based and therefore are susceptible to third-party cookie restrictions as well.
|
|
141
|
+
|
|
142
|
+
This approach is not recommended for most cases.
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
import { OAuth2Client, Credential } from '@okta/spa-platform';
|
|
146
|
+
import { AuthorizationCodeFlow } from '@okta/spa-platform/flows';
|
|
147
|
+
|
|
148
|
+
const client = new OAuth2Client({ ... });
|
|
149
|
+
|
|
150
|
+
const flow = new AuthorizationCodeFlow(client, {
|
|
151
|
+
redirectUri: REDIRECT_URI
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
export async function performSignIn () {
|
|
155
|
+
const { token } = await AuthorizationCodeFlow.PerformSilently(flow);
|
|
156
|
+
await Credential.store(token);
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### `PerformInPopup` [:book:](/api/spa-platform/flows/AuthorizationCodeFlow/#performinpopup)
|
|
161
|
+
|
|
162
|
+
> [!IMPORTANT]
|
|
163
|
+
> Read carefully before use. This method (and popup pattern at large) has quite a few "gotchas"
|
|
164
|
+
|
|
165
|
+
Fulfills `/authorize` requests in a popup window. Not necessarily recommended for primary authentication flows, but can be useful for step up authentication flows against known IDPs.
|
|
166
|
+
|
|
167
|
+
> [!NOTE]
|
|
168
|
+
> The phrase "external IDP" refers to an IDP other than the configured `issuer` for a given flow. See
|
|
169
|
+
> [Concepts: External Identity Providers](https://developer.okta.com/docs/concepts/identity-providers/) for a more detailed explanation
|
|
170
|
+
|
|
171
|
+
Utilizing external IDPs in a popup window will be susceptible to the IDP's [`Cross-Origin-Opener-Policy`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cross-Origin-Opener-Policy). Depending on their policy value, loading the IDP in a popup window may cause the popup window to create a new browsing context group ([BCG](https://developer.mozilla.org/en-US/docs/Glossary/Browsing_context)), seperate from the main browser window. The authentication flow will be unable to complete if this occurs. It's recommended to avoid using this method (and a popup in general) when utilizing external IDPs.
|
|
172
|
+
|
|
173
|
+
```ts
|
|
174
|
+
import { OAuth2Client, Credential } from '@okta/spa-platform';
|
|
175
|
+
import { AuthorizationCodeFlow } from '@okta/spa-platform/flows';
|
|
176
|
+
|
|
177
|
+
const client = new OAuth2Client({ ... });
|
|
178
|
+
|
|
179
|
+
const flow = new AuthorizationCodeFlow(client, {
|
|
180
|
+
redirectUri: REDIRECT_URI
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
export async function performSignIn () {
|
|
184
|
+
const result = await AuthorizationCodeFlow.PerformInPopup(flow);
|
|
185
|
+
|
|
186
|
+
if (result.completed) {
|
|
187
|
+
await Credential.store(result.token);
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
// handle unsuccessful auth
|
|
191
|
+
// `result.reason` - `'closed'` or `'blocked'`
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Session Logout Flow
|
|
197
|
+
|
|
198
|
+
Browser-specific ultilies methods for performing [OIDC RP-Initiated Logout](https://openid.net/specs/openid-connect-rpinitiated-1_0.html) in a browser environment.
|
|
199
|
+
|
|
200
|
+
### `PerformPostRedirect` [:book:](/api/spa-platform/flows/SessionLogoutFlow/#performpostredirect)
|
|
201
|
+
|
|
202
|
+
Performs a full-page redirect to IDP OIDC `end_session_endpoint` via generated hidden `<form method="POST">`.
|
|
203
|
+
|
|
204
|
+
Performing a `POST` request (instead of `GET` which supported by most IDPs) avoids leaking the `id_token` within the URL query params.
|