@pofsis-nbt/pofsis-auth 1.2.0 → 2.0.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/Documentation.md +143 -143
- package/README.md +130 -130
- package/dist/PofsisAuth.d.ts +1 -1
- package/dist/PofsisAuth.d.ts.map +1 -1
- package/dist/PofsisAuthClient-B3YHqgZL.cjs +2 -0
- package/dist/PofsisAuthClient-B3YHqgZL.cjs.map +1 -0
- package/dist/{PofsisAuthClient-c9BY8iNp.js → PofsisAuthClient-CEw_lL5S.js} +31 -80
- package/dist/PofsisAuthClient-CEw_lL5S.js.map +1 -0
- package/dist/{PofsisAuthModal-DIzzLJSP.cjs → RequireAuth-CPhXupYh.cjs} +2 -2
- package/dist/RequireAuth-CPhXupYh.cjs.map +1 -0
- package/dist/{PofsisAuthModal-DGbtRZ4f.js → RequireAuth-DFa8_MR1.js} +6 -98
- package/dist/RequireAuth-DFa8_MR1.js.map +1 -0
- package/dist/auth/authLaunch.d.ts +1 -2
- package/dist/auth/authLaunch.d.ts.map +1 -1
- package/dist/auth/config.d.ts.map +1 -1
- package/dist/components/index.d.ts +0 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/core/PofsisAuthClient.d.ts +0 -4
- package/dist/core/PofsisAuthClient.d.ts.map +1 -1
- package/dist/core/popupProtocol.d.ts.map +1 -1
- package/dist/core.cjs +1 -1
- package/dist/core.js +1 -1
- package/dist/elements.cjs +1 -1
- package/dist/elements.cjs.map +1 -1
- package/dist/elements.js +3 -3
- package/dist/elements.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/pofsis-auth-elements.js +1 -1
- package/dist/pofsis-auth-elements.js.map +1 -1
- package/dist/react/index.d.ts +2 -2
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react.cjs +1 -1
- package/dist/react.js +2 -2
- package/dist/types.d.ts +7 -21
- package/dist/types.d.ts.map +1 -1
- package/docs/popup-integration.md +162 -178
- package/package.json +87 -87
- package/dist/PofsisAuthClient-CRYYsJYc.cjs +0 -2
- package/dist/PofsisAuthClient-CRYYsJYc.cjs.map +0 -1
- package/dist/PofsisAuthClient-c9BY8iNp.js.map +0 -1
- package/dist/PofsisAuthModal-DGbtRZ4f.js.map +0 -1
- package/dist/PofsisAuthModal-DIzzLJSP.cjs.map +0 -1
- package/dist/components/PofsisAuthModal.d.ts +0 -3
- package/dist/components/PofsisAuthModal.d.ts.map +0 -1
|
@@ -1,178 +1,162 @@
|
|
|
1
|
-
# POFSIS Auth popup integration
|
|
2
|
-
|
|
3
|
-
`@pofsis-nbt/pofsis-auth` opens the hosted POFSIS Auth UI in a popup and completes OAuth 2.0 Authorization Code with PKCE in the calling tool. Passwords, OTPs, passkeys, refresh tokens, and Cognito credentials remain owned by POFSIS Auth.
|
|
4
|
-
|
|
5
|
-
## Prerequisites
|
|
6
|
-
|
|
7
|
-
- Register the tool's exact origin, callback URI, and logout URI with POFSIS Auth for each environment.
|
|
8
|
-
- Use HTTPS outside local development and allow the tool origin in Auth CORS configuration.
|
|
9
|
-
- Obtain the registered application
|
|
10
|
-
- Never put an OAuth client secret or organization service credential in a browser application.
|
|
11
|
-
|
|
12
|
-
## Package entry points
|
|
13
|
-
|
|
14
|
-
```bash
|
|
15
|
-
npm install @pofsis-nbt/pofsis-auth
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
| Import | Use |
|
|
19
|
-
| ---------------------------------- | ----------------------------------------------- |
|
|
20
|
-
| `@pofsis-nbt/pofsis-auth/core` | Framework-neutral browser SDK |
|
|
21
|
-
| `@pofsis-nbt/pofsis-auth/react` | React provider, hooks, guards, and API helper |
|
|
22
|
-
| `@pofsis-nbt/pofsis-auth/elements` | Optional `<pofsis-sign-in>` Web Component |
|
|
23
|
-
| `@pofsis-nbt/pofsis-auth` | Backward-compatible React API plus core exports |
|
|
24
|
-
|
|
25
|
-
## Framework-neutral setup
|
|
26
|
-
|
|
27
|
-
```js
|
|
28
|
-
import { createPofsisAuth, relayPopupCallback } from '@pofsis-nbt/pofsis-auth/core'
|
|
29
|
-
|
|
30
|
-
const auth = createPofsisAuth({
|
|
31
|
-
|
|
32
|
-
apiBaseUrl: 'https://auth-api.example.com',
|
|
33
|
-
authUrl: 'https://auth.example.com/authorize',
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
// Run this before rendering the normal app on /auth/callback.
|
|
37
|
-
if (location.pathname === '/auth/callback') {
|
|
38
|
-
const relayed = relayPopupCallback()
|
|
39
|
-
if (!relayed) {
|
|
40
|
-
const params = new URLSearchParams(location.search)
|
|
41
|
-
await auth.completeRedirectCallback(params.get('code'), params.get('state'))
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
Call popup authentication directly from a click or other user gesture:
|
|
47
|
-
|
|
48
|
-
```js
|
|
49
|
-
document.querySelector('#login').addEventListener('click', async () => {
|
|
50
|
-
const result = await auth.login({
|
|
51
|
-
presentation: 'popup',
|
|
52
|
-
screen: 'login',
|
|
53
|
-
returnUrl: location.pathname + location.search,
|
|
54
|
-
})
|
|
55
|
-
if (result.status === 'authenticated') renderUser(result.user)
|
|
56
|
-
})
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
The SDK calls `window.open()` itself. A blocked popup falls back to a full-page redirect. Route guards should explicitly use `presentation: 'redirect'` because they may not run during a user gesture.
|
|
60
|
-
|
|
61
|
-
## Initialization parameters
|
|
62
|
-
|
|
63
|
-
| Parameter | Required | Default | Meaning |
|
|
64
|
-
| ----------------- | -------: | ---------------------- | ---------------------------------- |
|
|
65
|
-
| `
|
|
66
|
-
| `apiBaseUrl` | yes | - | Public POFSIS Auth API base URL |
|
|
67
|
-
| `authUrl` | yes | - | Hosted Auth `/authorize` URL |
|
|
68
|
-
| `scope` | no | `openid profile email` | Registered OAuth scopes |
|
|
69
|
-
| `callbackPath` | no | `/auth/callback` | Local tool callback route |
|
|
70
|
-
| `popup.width` | no | `480` | Popup width in pixels |
|
|
71
|
-
| `popup.height` | no | `720` | Popup height in pixels |
|
|
72
|
-
| `popup.name` | no | `pofsis-auth` | Reused browser window name |
|
|
73
|
-
| `popup.timeoutMs` | no | `300000` | Authentication timeout |
|
|
74
|
-
|
|
75
|
-
## Launch parameters
|
|
76
|
-
|
|
77
|
-
| Parameter | Required | Default | Meaning |
|
|
78
|
-
| -------------- | -------: | ------------ | ---------------------------------------------------- |
|
|
79
|
-
| `presentation` | no | `popup` | `popup` or full-page `redirect` |
|
|
80
|
-
| `screen` | no | `login` | `login`, `signup`, or `reset` |
|
|
81
|
-
| `method` | no | Auth default | `password`, `passkey`, or `otp` |
|
|
82
|
-
| `loginHint` | no | - | Editable email or Philippine mobile hint |
|
|
83
|
-
| `returnUrl` | no | - | Safe application-relative route restored after login |
|
|
84
|
-
|
|
85
|
-
`returnUrl` must start with one `/` and must not start with `//`. Do not put invitation secrets or external URLs in it.
|
|
86
|
-
|
|
87
|
-
Convenience methods use the same protocol:
|
|
88
|
-
|
|
89
|
-
```js
|
|
90
|
-
await auth.signup({ loginHint: 'employee@example.com', method: 'otp' })
|
|
91
|
-
await auth.resetPassword({ loginHint: 'employee@example.com' })
|
|
92
|
-
await auth.login({ method: 'password' })
|
|
93
|
-
await auth.login({ method: 'passkey' })
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
## React
|
|
97
|
-
|
|
98
|
-
```tsx
|
|
99
|
-
import { PofsisAuth, useAuth } from '@pofsis-nbt/pofsis-auth/react'
|
|
100
|
-
import '@pofsis-nbt/pofsis-auth/style.css'
|
|
101
|
-
|
|
102
|
-
function SignInButton() {
|
|
103
|
-
const { login } = useAuth()
|
|
104
|
-
return <button onClick={() => void login({ presentation: 'popup' })}>Sign in</button>
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
export function App() {
|
|
108
|
-
return (
|
|
109
|
-
<PofsisAuth
|
|
110
|
-
|
|
111
|
-
apiBaseUrl="https://auth-api.example.com"
|
|
112
|
-
authUrl="https://auth.example.com/authorize"
|
|
113
|
-
>
|
|
114
|
-
<SignInButton />
|
|
115
|
-
</PofsisAuth>
|
|
116
|
-
)
|
|
117
|
-
}
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
`RequireAuth` deliberately uses redirect presentation. The provider handles popup and full-page callbacks at `callbackPath`.
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
```
|
|
127
|
-
<
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
unsubscribe()
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
Access tokens are held in memory. Use `getAccessToken()` to add a bearer token to the tool's own API calls. Do not write access tokens to URLs or browser storage.
|
|
167
|
-
|
|
168
|
-
## Results and failures
|
|
169
|
-
|
|
170
|
-
- `authenticated`: code exchange succeeded and includes the user.
|
|
171
|
-
- `cancelled`: the user closed the popup; this is not an authentication error.
|
|
172
|
-
- `redirecting`: the SDK started full-page navigation, including popup-blocked fallback.
|
|
173
|
-
- Invalid state, origin, popup source, or correlation messages are ignored or rejected.
|
|
174
|
-
- A timeout rejects the launch and closes the popup.
|
|
175
|
-
|
|
176
|
-
For callback URI mismatches, verify the exact deployed origin and registered URI. For CORS or silent-session failures, verify Auth's origin registry and credentialed cookie configuration. A cancelled or unavailable passkey remains an Auth-screen concern and must retain the password fallback.
|
|
177
|
-
|
|
178
|
-
The frontend SDK must never call `/api/internal`, Cognito administration APIs, or organization provisioning APIs. Those flows remain tool-backend to Auth-backend operations.
|
|
1
|
+
# POFSIS Auth popup integration
|
|
2
|
+
|
|
3
|
+
`@pofsis-nbt/pofsis-auth` opens the hosted POFSIS Auth UI in a popup and completes OAuth 2.0 Authorization Code with PKCE in the calling tool. Passwords, OTPs, passkeys, refresh tokens, and Cognito credentials remain owned by POFSIS Auth.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- Register the tool's exact origin, callback URI, and logout URI with POFSIS Auth for each environment.
|
|
8
|
+
- Use HTTPS outside local development and allow the tool origin in Auth CORS configuration.
|
|
9
|
+
- Obtain the immutable registered application UUID and allowed public scopes.
|
|
10
|
+
- Never put an OAuth client secret or organization service credential in a browser application.
|
|
11
|
+
|
|
12
|
+
## Package entry points
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install @pofsis-nbt/pofsis-auth
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
| Import | Use |
|
|
19
|
+
| ---------------------------------- | ----------------------------------------------- |
|
|
20
|
+
| `@pofsis-nbt/pofsis-auth/core` | Framework-neutral browser SDK |
|
|
21
|
+
| `@pofsis-nbt/pofsis-auth/react` | React provider, hooks, guards, and API helper |
|
|
22
|
+
| `@pofsis-nbt/pofsis-auth/elements` | Optional `<pofsis-sign-in>` Web Component |
|
|
23
|
+
| `@pofsis-nbt/pofsis-auth` | Backward-compatible React API plus core exports |
|
|
24
|
+
|
|
25
|
+
## Framework-neutral setup
|
|
26
|
+
|
|
27
|
+
```js
|
|
28
|
+
import { createPofsisAuth, relayPopupCallback } from '@pofsis-nbt/pofsis-auth/core'
|
|
29
|
+
|
|
30
|
+
const auth = createPofsisAuth({
|
|
31
|
+
applicationId: '11111111-1111-4111-8111-111111111111',
|
|
32
|
+
apiBaseUrl: 'https://auth-api.example.com',
|
|
33
|
+
authUrl: 'https://auth.example.com/authorize',
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
// Run this before rendering the normal app on /auth/callback.
|
|
37
|
+
if (location.pathname === '/auth/callback') {
|
|
38
|
+
const relayed = relayPopupCallback()
|
|
39
|
+
if (!relayed) {
|
|
40
|
+
const params = new URLSearchParams(location.search)
|
|
41
|
+
await auth.completeRedirectCallback(params.get('code'), params.get('state'))
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Call popup authentication directly from a click or other user gesture:
|
|
47
|
+
|
|
48
|
+
```js
|
|
49
|
+
document.querySelector('#login').addEventListener('click', async () => {
|
|
50
|
+
const result = await auth.login({
|
|
51
|
+
presentation: 'popup',
|
|
52
|
+
screen: 'login',
|
|
53
|
+
returnUrl: location.pathname + location.search,
|
|
54
|
+
})
|
|
55
|
+
if (result.status === 'authenticated') renderUser(result.user)
|
|
56
|
+
})
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The SDK calls `window.open()` itself. A blocked popup falls back to a full-page redirect. Route guards should explicitly use `presentation: 'redirect'` because they may not run during a user gesture.
|
|
60
|
+
|
|
61
|
+
## Initialization parameters
|
|
62
|
+
|
|
63
|
+
| Parameter | Required | Default | Meaning |
|
|
64
|
+
| ----------------- | -------: | ---------------------- | ---------------------------------- |
|
|
65
|
+
| `applicationId` | yes | - | Immutable `applications.id` UUID |
|
|
66
|
+
| `apiBaseUrl` | yes | - | Public POFSIS Auth API base URL |
|
|
67
|
+
| `authUrl` | yes | - | Hosted Auth `/authorize` URL |
|
|
68
|
+
| `scope` | no | `openid profile email` | Registered OAuth scopes |
|
|
69
|
+
| `callbackPath` | no | `/auth/callback` | Local tool callback route |
|
|
70
|
+
| `popup.width` | no | `480` | Popup width in pixels |
|
|
71
|
+
| `popup.height` | no | `720` | Popup height in pixels |
|
|
72
|
+
| `popup.name` | no | `pofsis-auth` | Reused browser window name |
|
|
73
|
+
| `popup.timeoutMs` | no | `300000` | Authentication timeout |
|
|
74
|
+
|
|
75
|
+
## Launch parameters
|
|
76
|
+
|
|
77
|
+
| Parameter | Required | Default | Meaning |
|
|
78
|
+
| -------------- | -------: | ------------ | ---------------------------------------------------- |
|
|
79
|
+
| `presentation` | no | `popup` | `popup` or full-page `redirect` |
|
|
80
|
+
| `screen` | no | `login` | `login`, `signup`, or `reset` |
|
|
81
|
+
| `method` | no | Auth default | `password`, `passkey`, or `otp` |
|
|
82
|
+
| `loginHint` | no | - | Editable email or Philippine mobile hint |
|
|
83
|
+
| `returnUrl` | no | - | Safe application-relative route restored after login |
|
|
84
|
+
|
|
85
|
+
`returnUrl` must start with one `/` and must not start with `//`. Do not put invitation secrets or external URLs in it.
|
|
86
|
+
|
|
87
|
+
Convenience methods use the same protocol:
|
|
88
|
+
|
|
89
|
+
```js
|
|
90
|
+
await auth.signup({ loginHint: 'employee@example.com', method: 'otp' })
|
|
91
|
+
await auth.resetPassword({ loginHint: 'employee@example.com' })
|
|
92
|
+
await auth.login({ method: 'password' })
|
|
93
|
+
await auth.login({ method: 'passkey' })
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## React
|
|
97
|
+
|
|
98
|
+
```tsx
|
|
99
|
+
import { PofsisAuth, useAuth } from '@pofsis-nbt/pofsis-auth/react'
|
|
100
|
+
import '@pofsis-nbt/pofsis-auth/style.css'
|
|
101
|
+
|
|
102
|
+
function SignInButton() {
|
|
103
|
+
const { login } = useAuth()
|
|
104
|
+
return <button onClick={() => void login({ presentation: 'popup' })}>Sign in</button>
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function App() {
|
|
108
|
+
return (
|
|
109
|
+
<PofsisAuth
|
|
110
|
+
applicationId="11111111-1111-4111-8111-111111111111"
|
|
111
|
+
apiBaseUrl="https://auth-api.example.com"
|
|
112
|
+
authUrl="https://auth.example.com/authorize"
|
|
113
|
+
>
|
|
114
|
+
<SignInButton />
|
|
115
|
+
</PofsisAuth>
|
|
116
|
+
)
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
`RequireAuth` deliberately uses redirect presentation. The provider handles popup and full-page callbacks at `callbackPath`.
|
|
121
|
+
|
|
122
|
+
## Web Component
|
|
123
|
+
|
|
124
|
+
Import the package entry or host the generated standalone `dist/pofsis-auth-elements.js` bundle:
|
|
125
|
+
|
|
126
|
+
```html
|
|
127
|
+
<script type="module" src="https://auth.pofsis.com/sdk/pofsis-auth-elements.js"></script>
|
|
128
|
+
|
|
129
|
+
<pofsis-sign-in
|
|
130
|
+
application-id="11111111-1111-4111-8111-111111111111"
|
|
131
|
+
api-base-url="https://auth-api.example.com"
|
|
132
|
+
auth-url="https://auth.example.com/authorize"
|
|
133
|
+
return-url="/dashboard"
|
|
134
|
+
>Sign in</pofsis-sign-in
|
|
135
|
+
>
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
The element dispatches `pofsis-auth-authenticated`, `pofsis-auth-cancelled`, `pofsis-auth-redirecting`, and `pofsis-auth-error`. It is only a launch control; credential fields always render on the hosted Auth origin.
|
|
139
|
+
|
|
140
|
+
## Session and API calls
|
|
141
|
+
|
|
142
|
+
```js
|
|
143
|
+
const unsubscribe = auth.subscribe((session) => updateHeader(session?.user))
|
|
144
|
+
const token = auth.getAccessToken()
|
|
145
|
+
await auth.refreshSession()
|
|
146
|
+
await auth.logout()
|
|
147
|
+
unsubscribe()
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Access tokens are held in memory. Use `getAccessToken()` to add a bearer token to the tool's own API calls. Do not write access tokens to URLs or browser storage.
|
|
151
|
+
|
|
152
|
+
## Results and failures
|
|
153
|
+
|
|
154
|
+
- `authenticated`: code exchange succeeded and includes the user.
|
|
155
|
+
- `cancelled`: the user closed the popup; this is not an authentication error.
|
|
156
|
+
- `redirecting`: the SDK started full-page navigation, including popup-blocked fallback.
|
|
157
|
+
- Invalid state, origin, popup source, or correlation messages are ignored or rejected.
|
|
158
|
+
- A timeout rejects the launch and closes the popup.
|
|
159
|
+
|
|
160
|
+
For callback URI mismatches, verify the exact deployed origin and registered URI. For CORS or silent-session failures, verify Auth's origin registry and credentialed cookie configuration. A cancelled or unavailable passkey remains an Auth-screen concern and must retain the password fallback.
|
|
161
|
+
|
|
162
|
+
The frontend SDK must never call `/api/internal`, Cognito administration APIs, or organization provisioning APIs. Those flows remain tool-backend to Auth-backend operations.
|
package/package.json
CHANGED
|
@@ -1,87 +1,87 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@pofsis-nbt/pofsis-auth",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "POFSIS OAuth/PKCE authentication SDK for browser applications.",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "./dist/index.cjs",
|
|
7
|
-
"module": "./dist/index.js",
|
|
8
|
-
"types": "./dist/index.d.ts",
|
|
9
|
-
"exports": {
|
|
10
|
-
".": {
|
|
11
|
-
"types": "./dist/index.d.ts",
|
|
12
|
-
"import": "./dist/index.js",
|
|
13
|
-
"require": "./dist/index.cjs",
|
|
14
|
-
"default": "./dist/index.js"
|
|
15
|
-
},
|
|
16
|
-
"./core": {
|
|
17
|
-
"types": "./dist/core/index.d.ts",
|
|
18
|
-
"import": "./dist/core.js",
|
|
19
|
-
"require": "./dist/core.cjs",
|
|
20
|
-
"default": "./dist/core.js"
|
|
21
|
-
},
|
|
22
|
-
"./react": {
|
|
23
|
-
"types": "./dist/react/index.d.ts",
|
|
24
|
-
"import": "./dist/react.js",
|
|
25
|
-
"require": "./dist/react.cjs",
|
|
26
|
-
"default": "./dist/react.js"
|
|
27
|
-
},
|
|
28
|
-
"./elements": {
|
|
29
|
-
"types": "./dist/elements/index.d.ts",
|
|
30
|
-
"import": "./dist/elements.js",
|
|
31
|
-
"require": "./dist/elements.cjs",
|
|
32
|
-
"default": "./dist/elements.js"
|
|
33
|
-
},
|
|
34
|
-
"./style.css": "./dist/style.css"
|
|
35
|
-
},
|
|
36
|
-
"files": [
|
|
37
|
-
"dist",
|
|
38
|
-
"README.md",
|
|
39
|
-
"Documentation.md",
|
|
40
|
-
"docs"
|
|
41
|
-
],
|
|
42
|
-
"sideEffects": [
|
|
43
|
-
"**/*.css"
|
|
44
|
-
],
|
|
45
|
-
"engines": {
|
|
46
|
-
"node": "^20.19.0 || >=22.12.0"
|
|
47
|
-
},
|
|
48
|
-
"scripts": {
|
|
49
|
-
"clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
50
|
-
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
51
|
-
"test": "tsx --test src/**/*.test.ts",
|
|
52
|
-
"check": "npm run typecheck && npm test",
|
|
53
|
-
"build": "npm run clean && vite build && vite build --config vite.elements.config.ts && tsc -p tsconfig.build.json",
|
|
54
|
-
"prepack": "npm run check && npm run build",
|
|
55
|
-
"pack:check": "npm pack --dry-run --json",
|
|
56
|
-
"format": "prettier --write .",
|
|
57
|
-
"format:check": "prettier --check ."
|
|
58
|
-
},
|
|
59
|
-
"peerDependencies": {
|
|
60
|
-
"axios": ">=1",
|
|
61
|
-
"react": ">=18",
|
|
62
|
-
"react-dom": ">=18"
|
|
63
|
-
},
|
|
64
|
-
"peerDependenciesMeta": {
|
|
65
|
-
"axios": {
|
|
66
|
-
"optional": true
|
|
67
|
-
},
|
|
68
|
-
"react": {
|
|
69
|
-
"optional": true
|
|
70
|
-
},
|
|
71
|
-
"react-dom": {
|
|
72
|
-
"optional": true
|
|
73
|
-
}
|
|
74
|
-
},
|
|
75
|
-
"devDependencies": {
|
|
76
|
-
"@types/node": "^26.0.0",
|
|
77
|
-
"@types/react": "^19.2.0",
|
|
78
|
-
"@types/react-dom": "^19.2.0",
|
|
79
|
-
"axios": "^1.19.0",
|
|
80
|
-
"prettier": "^3.6.0",
|
|
81
|
-
"react": "^19.2.0",
|
|
82
|
-
"react-dom": "^19.2.0",
|
|
83
|
-
"tsx": "^4.20.0",
|
|
84
|
-
"typescript": "^5.9.0",
|
|
85
|
-
"vite": "^8.2.0"
|
|
86
|
-
}
|
|
87
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@pofsis-nbt/pofsis-auth",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "POFSIS OAuth/PKCE authentication SDK for browser applications.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs",
|
|
14
|
+
"default": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./core": {
|
|
17
|
+
"types": "./dist/core/index.d.ts",
|
|
18
|
+
"import": "./dist/core.js",
|
|
19
|
+
"require": "./dist/core.cjs",
|
|
20
|
+
"default": "./dist/core.js"
|
|
21
|
+
},
|
|
22
|
+
"./react": {
|
|
23
|
+
"types": "./dist/react/index.d.ts",
|
|
24
|
+
"import": "./dist/react.js",
|
|
25
|
+
"require": "./dist/react.cjs",
|
|
26
|
+
"default": "./dist/react.js"
|
|
27
|
+
},
|
|
28
|
+
"./elements": {
|
|
29
|
+
"types": "./dist/elements/index.d.ts",
|
|
30
|
+
"import": "./dist/elements.js",
|
|
31
|
+
"require": "./dist/elements.cjs",
|
|
32
|
+
"default": "./dist/elements.js"
|
|
33
|
+
},
|
|
34
|
+
"./style.css": "./dist/style.css"
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"dist",
|
|
38
|
+
"README.md",
|
|
39
|
+
"Documentation.md",
|
|
40
|
+
"docs"
|
|
41
|
+
],
|
|
42
|
+
"sideEffects": [
|
|
43
|
+
"**/*.css"
|
|
44
|
+
],
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": "^20.19.0 || >=22.12.0"
|
|
47
|
+
},
|
|
48
|
+
"scripts": {
|
|
49
|
+
"clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
50
|
+
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
51
|
+
"test": "tsx --test src/**/*.test.ts",
|
|
52
|
+
"check": "npm run typecheck && npm test",
|
|
53
|
+
"build": "npm run clean && vite build && vite build --config vite.elements.config.ts && tsc -p tsconfig.build.json",
|
|
54
|
+
"prepack": "npm run check && npm run build",
|
|
55
|
+
"pack:check": "npm pack --dry-run --json",
|
|
56
|
+
"format": "prettier --write .",
|
|
57
|
+
"format:check": "prettier --check ."
|
|
58
|
+
},
|
|
59
|
+
"peerDependencies": {
|
|
60
|
+
"axios": ">=1",
|
|
61
|
+
"react": ">=18",
|
|
62
|
+
"react-dom": ">=18"
|
|
63
|
+
},
|
|
64
|
+
"peerDependenciesMeta": {
|
|
65
|
+
"axios": {
|
|
66
|
+
"optional": true
|
|
67
|
+
},
|
|
68
|
+
"react": {
|
|
69
|
+
"optional": true
|
|
70
|
+
},
|
|
71
|
+
"react-dom": {
|
|
72
|
+
"optional": true
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
"devDependencies": {
|
|
76
|
+
"@types/node": "^26.0.0",
|
|
77
|
+
"@types/react": "^19.2.0",
|
|
78
|
+
"@types/react-dom": "^19.2.0",
|
|
79
|
+
"axios": "^1.19.0",
|
|
80
|
+
"prettier": "^3.6.0",
|
|
81
|
+
"react": "^19.2.0",
|
|
82
|
+
"react-dom": "^19.2.0",
|
|
83
|
+
"tsx": "^4.20.0",
|
|
84
|
+
"typescript": "^5.9.0",
|
|
85
|
+
"vite": "^8.2.0"
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
async function e(e){if(e.status===204)return null;let t=await e.text();return t?JSON.parse(t):null}async function t(t,n,r){let i=await fetch(`${t.apiBaseUrl}${n}`,{credentials:`include`,...r,headers:{Accept:`application/json`,...r?.body&&!(r.body instanceof FormData)?{"Content-Type":`application/json`}:{},...r?.headers}});if(!i.ok){let e=Error(`Auth API ${n} failed (${i.status})`);throw e.status=i.status,e}return{status:i.status,data:await e(i)}}async function n(e){let{data:n}=await t(e,`/oauth/clients/${encodeURIComponent(e.appName.toUpperCase())}?origin=${encodeURIComponent(window.location.origin)}`);return n}async function r(e,n,r,i){let{data:a}=await t(e,`/oauth/token`,{method:`POST`,body:JSON.stringify({grant_type:`authorization_code`,client_id:i.client_id,redirect_uri:i.redirect_uri,code:n,code_verifier:r})});return a}async function i(e,n){let{data:r}=await t(e,`/oauth/token`,{method:`POST`,body:JSON.stringify({grant_type:`refresh_token`,client_id:n})});return r||null}async function a(e){try{return await t(e,`/auth/session`),!0}catch{return!1}}async function o(e){await t(e,`/auth/logout`,{method:`POST`})}async function s(e,n){let{data:r}=await t(e,`/auth/profile/me`,{headers:{Authorization:`Bearer ${n}`}});return r}async function c(e,n,r){let{data:i}=await t(e,`/auth/profile/me`,{method:`PATCH`,headers:{Authorization:`Bearer ${n}`},body:JSON.stringify(r)});return i}async function l(e,n,r,i){let a=new FormData;a.append(`file`,i);let{data:o}=await t(e,`/auth/profile/me/images/${r}`,{method:`POST`,headers:{Authorization:`Bearer ${n}`},body:a});return o}async function u(e,n,r){let{data:i}=await t(e,`/auth/profile/me/images/${r}`,{method:`DELETE`,headers:{Authorization:`Bearer ${n}`}});return i}function d(e){return e.replace(/\/$/,``)}function f(e={}){let t=e.appName?.trim(),n=e.apiBaseUrl?.trim(),r=e.authUrl?.trim(),i=e.scope?.trim()||`openid profile email`,a=e.callbackPath?.trim()||`/auth/callback`,o={width:e.popup?.width??480,height:e.popup?.height??720,name:e.popup?.name?.trim()||`pofsis-auth`,timeoutMs:e.popup?.timeoutMs??3e5},s=[];if(t||s.push(`appName`),n||s.push(`apiBaseUrl`),r||s.push(`authUrl`),s.length)throw Error(`@pofsis-nbt/pofsis-auth missing config: ${s.join(`, `)}`);if(!t||!n||!r)throw Error(`@pofsis-nbt/pofsis-auth missing config`);if(!a.startsWith(`/`)||a.startsWith(`//`))throw Error(`@pofsis-nbt/pofsis-auth callbackPath must be application-relative`);if(o.width<=0||o.height<=0||o.timeoutMs<=0)throw Error(`@pofsis-nbt/pofsis-auth popup dimensions and timeout must be positive`);return{appName:t,apiBaseUrl:d(n),authUrl:d(r),scope:i,callbackPath:a,popup:o}}var p=/^[^\s@]+@[^\s@]+\.[^\s@]+$/,m=/^(?:\+63|63|0)?9\d{9}$/,h=new Set([`password`,`passkey`,`otp`]),g=new Set([`login`,`signup`,`reset`]),_=320;function v(e,t=!1){let n=typeof e==`string`?e.trim():``;if(!n||n.length>_)return;if(p.test(n))return n.toLowerCase();let r=n.replace(/[\s()-]/g,``);if(!t&&m.test(r))return`+63${r.replace(/^(?:\+63|63|0)/,``)}`}function y(e,t=`login`){let n=typeof e==`string`?{returnUrl:e}:e||{},r=n.screen===`register`?`signup`:n.screen,i=g.has(r)?r:t,a=h.has(n.method)?n.method:void 0,o=i===`login`||i===`signup`&&(a===`password`||a===`otp`)?a:void 0;return{returnUrl:n.returnUrl,screen:i,loginHint:v(n.loginHint),method:o}}function b(e){let t=new URLSearchParams(e),n=t.get(`login_hint`),r=n===null?v(t.get(`email`),!0):v(n);return y({screen:t.get(`screen`)||void 0,loginHint:r,method:t.get(`method`)||void 0})}function x({authUrl:e,appName:t,query:n,options:r}){let i=y(r),a=new URL(e);if(a.search=n.toString(),i.loginHint&&a.searchParams.set(`login_hint`,i.loginHint),i.screen===`login`&&i.method&&a.searchParams.set(`method`,i.method),i.screen===`login`)return a.toString();let o=i.screen===`signup`?`/signup`:`/forgot-password`,s=new URL(o,a);return s.searchParams.set(`app`,t),s.searchParams.set(`return_to`,`${a.pathname}${a.search}`),i.loginHint&&s.searchParams.set(`login_hint`,i.loginHint),i.screen===`signup`&&s.searchParams.set(`method`,i.method||`password`),s.toString()}var S=`pofsis-auth:callback`;function C(e){if(!e)return;let t=e.indexOf(`.`);return t>0?e.slice(0,t):void 0}function w(e=window.location.origin){let t=window.opener&&!window.opener.closed?window.opener:window.parent===window?null:window.parent;if(!t)return!1;let n=new URLSearchParams(window.location.search),r=n.get(`state`)||void 0,i={type:S,code:n.get(`code`)||void 0,state:r,error:n.get(`error`)||void 0,correlationId:C(r||null)};return t.postMessage(i,e),t===window.opener&&window.close(),!0}var T=e=>btoa(String.fromCharCode(...e)).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/,``),E=()=>T(crypto.getRandomValues(new Uint8Array(32)));async function D(e){return T(new Uint8Array(await crypto.subtle.digest(`SHA-256`,new TextEncoder().encode(e))))}var O=e=>e?.startsWith(`/`)&&!e.startsWith(`//`)?e:void 0,k=e=>({token_type:e.token_type,expires_in:e.expires_in,user:e.user}),A=class{config;token=null;session=null;client=null;clientPromise=null;refreshPromise=null;subscribers=new Set;attempt=null;iframeAttempt=null;listening=!1;constructor(e){this.config=f(e),this.attach()}attach(){this.listening||=(window.addEventListener(`message`,this.onPopupMessage),!0)}destroy(){window.removeEventListener(`message`,this.onPopupMessage),this.listening=!1;let e=this.finishAttempt();e&&(e.popup.close(),e.resolve({status:`cancelled`})),this.cancelIframeLogin(),this.subscribers.clear()}getUser(){return this.session?.user??null}getSession(){return this.session}getAccessToken(){return this.token}subscribe(e){return this.attach(),this.subscribers.add(e),e(this.session),()=>{this.subscribers.delete(e)}}emit(){for(let e of this.subscribers)e(this.session)}accept(e){this.token=e.access_token,this.session=k(e),this.emit()}loadClient(){return this.clientPromise||=n(this.config).then(e=>this.client=e).catch(e=>{throw this.clientPromise=null,e}),this.clientPromise}getOAuthClient(){return this.loadClient()}async refreshSession(){let e=await this.loadClient();return this.refreshPromise||=i(this.config,e.client_id).then(e=>{e?this.accept(e):this.clearSession()}).finally(()=>this.refreshPromise=null),this.refreshPromise}async isRemoteSessionActive(){return a(this.config)}clearSession(){this.token=null,this.session=null,this.emit()}replaceUser(e){this.session&&(this.session={...this.session,user:e},this.emit())}async logout(){try{await o(this.config)}finally{this.clearSession()}}signup(e={}){return this.login({...e,screen:`signup`})}resetPassword(e={}){return this.login({...e,screen:`reset`})}async login(e={}){let t=y(e),n=e.presentation??`popup`;return n===`popup`?this.openPopup({...e,...t}):n===`iframe`?this.openIframe({...e,...t}):this.startRedirect({...e,...t})}cancelIframeLogin(){this.finishIframeAttempt()?.resolve({status:`cancelled`})}openIframe(e){let t=e.target;if(!t)return Promise.reject(Error(`POFSIS Auth iframe target is required.`));this.cancelIframeLogin();let n=E(),r=`${n}.${E()}`,i=E(),a=O(e.returnUrl);return new Promise((o,s)=>{let c=setTimeout(()=>{this.finishIframeAttempt()?.reject(Error(`POFSIS Auth iframe timed out.`))},this.config.popup.timeoutMs);this.iframeAttempt={frame:t,state:r,verifier:i,correlationId:n,returnUrl:a,resolve:o,reject:s,timeout:c},this.authorizationUrl(e,r,i).then(e=>t.contentWindow?.location.replace(e)).catch(e=>{this.finishIframeAttempt()?.reject(e instanceof Error?e:Error(String(e)))})})}async authorizationUrl(e,t,n){let r=await this.loadClient(),i=new URLSearchParams({app:this.config.appName.toUpperCase(),client_id:r.client_id,redirect_uri:r.redirect_uri,response_type:`code`,scope:this.config.scope,state:t,code_challenge:await D(n),code_challenge_method:`S256`});return x({authUrl:this.config.authUrl,appName:this.config.appName.toUpperCase(),query:i,options:e})}storageKey(e){return`${this.config.appName.toLowerCase()}.auth.${e}`}async startRedirect(e){let t=E(),n=E();sessionStorage.setItem(this.storageKey(`state`),t),sessionStorage.setItem(this.storageKey(`verifier`),n);let r=O(e.returnUrl);return r?sessionStorage.setItem(this.storageKey(`return-path`),r):sessionStorage.removeItem(this.storageKey(`return-path`)),window.location.assign(await this.authorizationUrl(e,t,n)),{status:`redirecting`}}async openPopup(e){if(this.attempt&&!this.attempt.popup.closed)return this.attempt.popup.focus(),new Promise((e,t)=>{let n=this.attempt,r=n.resolve,i=n.reject;n.resolve=t=>{r(t),e(t)},n.reject=e=>{i(e),t(e)}});let{width:t,height:n,name:r,timeoutMs:i}=this.config.popup,a=Math.max(0,window.screenX+(window.outerWidth-t)/2),o=Math.max(0,window.screenY+(window.outerHeight-n)/2),s=window.open(`about:blank`,r,`popup=yes,width=${t},height=${n},left=${Math.round(a)},top=${Math.round(o)}`);if(!s)return this.startRedirect({...e,presentation:`redirect`});let c=E(),l=`${c}.${E()}`,u=E(),d=O(e.returnUrl);return new Promise((t,n)=>{let r=setInterval(()=>{s.closed&&this.finishAttempt()?.resolve({status:`cancelled`})},250),a=setTimeout(()=>{let e=this.finishAttempt();s.close(),e?.reject(Error(`POFSIS Auth popup timed out.`))},i);this.attempt={popup:s,state:l,verifier:u,correlationId:c,returnUrl:d,resolve:t,reject:n,timer:r,timeout:a},this.authorizationUrl(e,l,u).then(e=>s.location.replace(e)).catch(e=>{let t=this.finishAttempt();s.close(),t?.reject(e instanceof Error?e:Error(String(e)))})})}finishAttempt(){let e=this.attempt;return e?(clearInterval(e.timer),clearTimeout(e.timeout),this.attempt=null,e):null}finishIframeAttempt(){let e=this.iframeAttempt;return e?(clearTimeout(e.timeout),this.iframeAttempt=null,e):null}onPopupMessage=e=>{let t=this.iframeAttempt;if(t&&e.origin===window.location.origin&&e.source===t.frame.contentWindow&&e.data?.type===`pofsis-auth:callback`&&e.data.correlationId===t.correlationId&&C(e.data.state||null)===t.correlationId&&e.data.state===t.state){let t=this.finishIframeAttempt();if(e.data.error||!e.data.code){t.reject(Error(e.data.error||`POFSIS Auth callback was incomplete.`));return}this.completeCode(e.data.code,e.data.state,t.verifier).then(()=>t.resolve({status:`authenticated`,user:this.getUser()})).catch(e=>t.reject(e instanceof Error?e:Error(String(e))));return}let n=this.attempt,r=e.data;if(!n||e.origin!==window.location.origin||e.source!==n.popup||r?.type!==`pofsis-auth:callback`||r.correlationId!==n.correlationId||C(r.state||null)!==n.correlationId||r.state!==n.state)return;let i=this.finishAttempt();if(i){if(r.error||!r.code){i.popup.close(),i.reject(Error(r.error||`POFSIS Auth callback was incomplete.`));return}this.completeCode(r.code,r.state,i.verifier).then(()=>{i.popup.close(),i.returnUrl&&window.history.replaceState(null,``,i.returnUrl),i.resolve({status:`authenticated`,user:this.getUser()})}).catch(e=>{i.popup.close(),i.reject(e instanceof Error?e:Error(String(e)))})}};async completeCode(e,t,n){if(!t||!n)throw Error(`Authentication state could not be verified.`);let i=await this.loadClient();this.accept(await r(this.config,e,n,i))}async completeRedirectCallback(e,t){let n=sessionStorage.getItem(this.storageKey(`state`)),r=sessionStorage.getItem(this.storageKey(`verifier`));if(sessionStorage.removeItem(this.storageKey(`state`)),sessionStorage.removeItem(this.storageKey(`verifier`)),!n||!r||t!==n)throw Error(`Authentication state could not be verified.`);await this.completeCode(e,t,r)}};function j(e){return new A(e)}Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return f}}),Object.defineProperty(exports,"c",{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return b}}),Object.defineProperty(exports,"l",{enumerable:!0,get:function(){return l}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return j}}),Object.defineProperty(exports,"o",{enumerable:!0,get:function(){return u}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return w}}),Object.defineProperty(exports,"s",{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return A}});
|
|
2
|
-
//# sourceMappingURL=PofsisAuthClient-CRYYsJYc.cjs.map
|