@owlmeans/client-auth 0.1.1 → 0.1.3
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/LICENSE +1 -1
- package/README.md +32 -489
- package/build/components/dispatcher/component.d.ts.map +1 -1
- package/build/components/dispatcher/component.js +5 -2
- package/build/components/dispatcher/component.js.map +1 -1
- package/build/components/dispatcher/types.d.ts +3 -1
- package/build/components/dispatcher/types.d.ts.map +1 -1
- package/build/helper.d.ts +4 -4
- package/build/helper.d.ts.map +1 -1
- package/build/helper.js +15 -14
- package/build/helper.js.map +1 -1
- package/build/manager/components/authentication/control.js +4 -4
- package/build/manager/components/authentication/control.js.map +1 -1
- package/build/manager/modules.d.ts +1 -1
- package/build/manager/modules.d.ts.map +1 -1
- package/build/manager/modules.js +1 -1
- package/build/manager/modules.js.map +1 -1
- package/build/modules.d.ts +2 -2
- package/build/modules.d.ts.map +1 -1
- package/build/modules.js +1 -1
- package/build/modules.js.map +1 -1
- package/build/service.js +1 -1
- package/build/service.js.map +1 -1
- package/package.json +26 -21
- package/src/components/dispatcher/component.tsx +5 -2
- package/src/components/dispatcher/types.ts +3 -1
- package/src/helper.ts +18 -16
- package/src/manager/components/authentication/control.ts +5 -5
- package/src/manager/modules.ts +1 -1
- package/src/modules.ts +3 -3
- package/src/service.ts +2 -2
- package/tests/context.ts +27 -0
- package/tests/service.spec.ts +138 -0
- package/tests/tsconfig.json +12 -0
- package/tsconfig.json +6 -10
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { describe, test, expect } from 'bun:test'
|
|
2
|
+
import { makeTestContext } from './context.js'
|
|
3
|
+
import { makeFixtureKeyPair } from '@owlmeans/test-auth'
|
|
4
|
+
import { EnvelopeKind, makeEnvelopeModel } from '@owlmeans/basic-envelope'
|
|
5
|
+
import { AuthorizationError, AuthroizationType, AuthRole } from '@owlmeans/auth'
|
|
6
|
+
import type { Auth } from '@owlmeans/auth'
|
|
7
|
+
import { DEFAULT_ALIAS, AUTH_RESOURCE, USER_ID } from '../src/consts.js'
|
|
8
|
+
import type { AuthService } from '@owlmeans/auth-common'
|
|
9
|
+
import type { Resource } from '@owlmeans/resource'
|
|
10
|
+
import type { ClientAuthRecord } from '../src/types.js'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Produce a valid bearer token (as server-auth would issue)
|
|
14
|
+
*/
|
|
15
|
+
const makeBearer = async (auth: Partial<Auth>) => {
|
|
16
|
+
const appKP = makeFixtureKeyPair('client-auth-app-key')
|
|
17
|
+
const fullAuth: Auth = {
|
|
18
|
+
token: 'nonce-123',
|
|
19
|
+
userId: 'user-1',
|
|
20
|
+
scopes: ['*'],
|
|
21
|
+
role: AuthRole.User,
|
|
22
|
+
type: AuthroizationType.Ed25519BasicToken,
|
|
23
|
+
source: 'test-service',
|
|
24
|
+
isUser: true,
|
|
25
|
+
createdAt: new Date(),
|
|
26
|
+
...auth,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const signed = await makeEnvelopeModel<Auth>(AuthroizationType.Ed25519BasicToken)
|
|
30
|
+
.send(fullAuth, null).sign(appKP, EnvelopeKind.Token)
|
|
31
|
+
|
|
32
|
+
return `${AuthroizationType.Ed25519BasicToken.toUpperCase()} ${signed}`
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const initContext = async () => {
|
|
36
|
+
const context = makeTestContext()
|
|
37
|
+
context.configure()
|
|
38
|
+
await context.init()
|
|
39
|
+
return context
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
describe('@owlmeans/client-auth — update', () => {
|
|
43
|
+
test('stores token and parses Auth from bearer', async () => {
|
|
44
|
+
const context = await initContext()
|
|
45
|
+
const authService = context.service<AuthService>(DEFAULT_ALIAS)
|
|
46
|
+
|
|
47
|
+
const bearer = await makeBearer({ userId: 'user-update-test', scopes: ['read'] })
|
|
48
|
+
await authService.update(bearer)
|
|
49
|
+
|
|
50
|
+
// Token should be stored in memory
|
|
51
|
+
expect(authService.token).toBe(bearer)
|
|
52
|
+
|
|
53
|
+
// Auth should be parsed from the envelope
|
|
54
|
+
expect(authService.auth).not.toBeUndefined()
|
|
55
|
+
expect(authService.auth!.userId).toBe('user-update-test')
|
|
56
|
+
expect(authService.auth!.scopes).toEqual(['read'])
|
|
57
|
+
|
|
58
|
+
// Token should be persisted in the resource store
|
|
59
|
+
const store = context.resource<Resource<ClientAuthRecord>>(AUTH_RESOURCE)
|
|
60
|
+
const record = await store.load(USER_ID)
|
|
61
|
+
expect(record).not.toBeNull()
|
|
62
|
+
expect(record!.token).toBe(bearer)
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
test('clears auth when token is null', async () => {
|
|
66
|
+
const context = await initContext()
|
|
67
|
+
const authService = context.service<AuthService>(DEFAULT_ALIAS)
|
|
68
|
+
|
|
69
|
+
// First set a valid token
|
|
70
|
+
const bearer = await makeBearer({ userId: 'user-to-clear' })
|
|
71
|
+
await authService.update(bearer)
|
|
72
|
+
expect(authService.auth).not.toBeUndefined()
|
|
73
|
+
|
|
74
|
+
// Now clear it
|
|
75
|
+
await authService.update(null as any)
|
|
76
|
+
|
|
77
|
+
expect(authService.token).toBeNull()
|
|
78
|
+
expect(authService.auth).toBeUndefined()
|
|
79
|
+
})
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
describe('@owlmeans/client-auth — authenticated', () => {
|
|
83
|
+
test('returns null when no token exists', async () => {
|
|
84
|
+
const context = await initContext()
|
|
85
|
+
const authService = context.service<AuthService>(DEFAULT_ALIAS)
|
|
86
|
+
|
|
87
|
+
const result = await authService.authenticated()
|
|
88
|
+
expect(result).toBeNull()
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
test('loads token from storage on first call', async () => {
|
|
92
|
+
const context = await initContext()
|
|
93
|
+
const authService = context.service<AuthService>(DEFAULT_ALIAS)
|
|
94
|
+
|
|
95
|
+
// Pre-populate storage directly (simulating previous session)
|
|
96
|
+
const bearer = await makeBearer({ userId: 'persisted-user' })
|
|
97
|
+
const store = context.resource<Resource<ClientAuthRecord>>(AUTH_RESOURCE)
|
|
98
|
+
await store.create({ id: USER_ID, token: bearer })
|
|
99
|
+
|
|
100
|
+
// Now call authenticated — it should load from store
|
|
101
|
+
const result = await authService.authenticated()
|
|
102
|
+
expect(result).toBe(bearer)
|
|
103
|
+
expect(authService.auth).not.toBeUndefined()
|
|
104
|
+
expect(authService.auth!.userId).toBe('persisted-user')
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
test('returns in-memory token without re-reading storage', async () => {
|
|
108
|
+
const context = await initContext()
|
|
109
|
+
const authService = context.service<AuthService>(DEFAULT_ALIAS)
|
|
110
|
+
|
|
111
|
+
const bearer = await makeBearer({ userId: 'memory-user' })
|
|
112
|
+
await authService.update(bearer)
|
|
113
|
+
|
|
114
|
+
const result = await authService.authenticated()
|
|
115
|
+
expect(result).toBe(bearer)
|
|
116
|
+
})
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
describe('@owlmeans/client-auth — user', () => {
|
|
120
|
+
test('throws AuthorizationError when not authenticated', async () => {
|
|
121
|
+
const context = await initContext()
|
|
122
|
+
const authService = context.service<AuthService>(DEFAULT_ALIAS)
|
|
123
|
+
|
|
124
|
+
expect(() => authService.user()).toThrow(AuthorizationError)
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
test('returns Auth after update', async () => {
|
|
128
|
+
const context = await initContext()
|
|
129
|
+
const authService = context.service<AuthService>(DEFAULT_ALIAS)
|
|
130
|
+
|
|
131
|
+
const bearer = await makeBearer({ userId: 'user-for-user-call', role: AuthRole.Guest })
|
|
132
|
+
await authService.update(bearer)
|
|
133
|
+
|
|
134
|
+
const auth = authService.user()
|
|
135
|
+
expect(auth.userId).toBe('user-for-user-call')
|
|
136
|
+
expect(auth.role).toBe(AuthRole.Guest)
|
|
137
|
+
})
|
|
138
|
+
})
|
package/tsconfig.json
CHANGED
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"extends": [
|
|
3
|
-
"
|
|
4
|
-
"
|
|
3
|
+
"@owlmeans/dep-config/tsconfig.base.json",
|
|
4
|
+
"@owlmeans/dep-config/tsconfig.react.json"
|
|
5
5
|
],
|
|
6
6
|
"compilerOptions": {
|
|
7
|
-
"rootDir": "./src/",
|
|
8
|
-
"outDir": "./build/"
|
|
7
|
+
"rootDir": "./src/",
|
|
8
|
+
"outDir": "./build/"
|
|
9
9
|
},
|
|
10
|
-
"exclude": [
|
|
11
|
-
|
|
12
|
-
"./build/**/*",
|
|
13
|
-
"./*.ts"
|
|
14
|
-
]
|
|
15
|
-
}
|
|
10
|
+
"exclude": ["./dist/**/*", "./build/**/*", "./tests/**/*", "./*.ts"]
|
|
11
|
+
}
|