@owlmeans/server-oidc-rp 0.1.2 → 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/README.md +59 -474
- package/build/actions/init.d.ts +2 -2
- package/build/actions/init.d.ts.map +1 -1
- package/build/actions/init.js +2 -2
- package/build/actions/init.js.map +1 -1
- package/build/actions/process.d.ts +2 -2
- package/build/actions/process.d.ts.map +1 -1
- package/build/actions/process.js.map +1 -1
- package/build/auth/plugins/google-client.d.ts +4 -0
- package/build/auth/plugins/google-client.d.ts.map +1 -0
- package/build/auth/plugins/google-client.js +147 -0
- package/build/auth/plugins/google-client.js.map +1 -0
- package/build/auth/plugins/index.d.ts.map +1 -1
- package/build/auth/plugins/index.js +3 -1
- package/build/auth/plugins/index.js.map +1 -1
- package/build/gate.d.ts +1 -1
- package/build/gate.d.ts.map +1 -1
- package/build/guard.d.ts +2 -2
- package/build/guard.d.ts.map +1 -1
- package/build/guard.js +1 -1
- package/build/guard.js.map +1 -1
- package/build/index.d.ts +1 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js.map +1 -1
- package/build/model/gate.js +1 -1
- package/build/model/gate.js.map +1 -1
- package/build/modules.d.ts +2 -2
- package/build/modules.d.ts.map +1 -1
- package/build/modules.js +3 -3
- package/build/modules.js.map +1 -1
- package/build/service.d.ts.map +1 -1
- package/build/service.js +15 -7
- package/build/service.js.map +1 -1
- package/build/types.d.ts +44 -7
- package/build/types.d.ts.map +1 -1
- package/build/utils/auth.d.ts +2 -2
- package/build/utils/auth.d.ts.map +1 -1
- package/build/utils/auth.js.map +1 -1
- package/build/utils/types.d.ts +3 -2
- package/build/utils/types.d.ts.map +1 -1
- package/build/wrapper.js +2 -2
- package/build/wrapper.js.map +1 -1
- package/package.json +24 -20
- package/src/actions/init.ts +5 -5
- package/src/actions/process.ts +2 -2
- package/src/auth/plugins/google-client.ts +189 -0
- package/src/auth/plugins/index.ts +3 -1
- package/src/gate.ts +1 -1
- package/src/guard.ts +3 -3
- package/src/index.ts +17 -1
- package/src/model/gate.ts +2 -2
- package/src/modules.ts +6 -6
- package/src/service.ts +22 -12
- package/src/types.ts +67 -8
- package/src/utils/auth.ts +2 -3
- package/src/utils/types.ts +3 -2
- package/src/wrapper.ts +8 -8
- package/tests/context.ts +44 -0
- package/tests/google-client.spec.ts +123 -0
- package/tests/service.spec.ts +75 -0
- package/tests/tsconfig.json +12 -0
- package/tsconfig.json +6 -5
- package/build/.gitkeep +0 -0
package/build/wrapper.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wrapper.js","sourceRoot":"","sources":["../src/wrapper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAE3E,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAC1E,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAEjD,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AACjE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAEnD,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA;AAClG,OAAO,IAAI,MAAM,OAAO,CAAA;AAExB,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAA;AAEnD,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAuB,EAAE;IAC9D,MAAM,OAAO,GAAG,aAAa,CAAqB,YAAY,EAAE;QAC9D,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YAC3B,MAAM,GAAG,GAAG,OAAO,CAAC,SAAS,EAAmB,CAAA;YAChD,KAAK,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,KAAK,CAAA;YACxD,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;gBAClB,MAAM,IAAI,kBAAkB,CAAC,OAAO,CAAC,CAAA;YACvC,CAAC;YACD,MAAM,CAAC,EAAE,cAAc,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;YAC3C,MAAM,QAAQ,GAAG,iBAAiB,CAAO,cAAc,EAAE,YAAY,CAAC,KAAK,CAAC,CAAA;YAC5E,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAA;YAE/B,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAA;gBAC1D,IAAI,MAAM,IAAI,IAAI,IAAI,MAAM,CAAC,OAAO,IAAI,IAAI,EAAE,CAAC;oBAC7C,MAAM,IAAI,kBAAkB,CAAC,QAAQ,CAAC,CAAA;gBACxC,CAAC;gBAED,IAAI,MAAM,CAAC,SAAS,IAAI,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC;qBACnD,GAAG,CAAC,mBAAmB,EAAE,cAAc,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;oBACtD,OAAO,EAAE,KAAK,EAAE,CAAA;gBAClB,CAAC;gBAED,MAAM,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAA;gBAE7B,IAAI,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"wrapper.js","sourceRoot":"","sources":["../src/wrapper.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owlmeans/server-oidc-rp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"build": "tsc -b",
|
|
8
8
|
"dev": "sleep 312 && nodemon -e ts,tsx,json --watch src --exec \"tsc -p ./tsconfig.json\"",
|
|
9
|
-
"watch": "tsc -b -w --preserveWatchOutput --pretty"
|
|
9
|
+
"watch": "tsc -b -w --preserveWatchOutput --pretty",
|
|
10
|
+
"test": "bun test ./tests"
|
|
10
11
|
},
|
|
11
12
|
"main": "build/index.js",
|
|
12
13
|
"module": "build/index.js",
|
|
@@ -35,32 +36,35 @@
|
|
|
35
36
|
}
|
|
36
37
|
},
|
|
37
38
|
"devDependencies": {
|
|
39
|
+
"@owlmeans/dep-config": "workspace:*",
|
|
40
|
+
"@owlmeans/test-auth": "^0.1.2",
|
|
41
|
+
"@types/bun": "^1.3.0",
|
|
38
42
|
"@types/node": "^24.10.1",
|
|
39
43
|
"nodemon": "^3.1.11",
|
|
40
44
|
"npm-check": "^6.0.1",
|
|
41
|
-
"typescript": "^
|
|
45
|
+
"typescript": "^6.0.2"
|
|
42
46
|
},
|
|
43
47
|
"dependencies": {
|
|
44
48
|
"@noble/hashes": "^1.5.0",
|
|
45
|
-
"@owlmeans/auth": "^0.1.
|
|
46
|
-
"@owlmeans/auth-common": "^0.1.
|
|
47
|
-
"@owlmeans/basic-envelope": "^0.1.
|
|
48
|
-
"@owlmeans/client-
|
|
49
|
-
"@owlmeans/config": "^0.1.
|
|
50
|
-
"@owlmeans/context": "^0.1.
|
|
51
|
-
"@owlmeans/did": "^0.1.
|
|
52
|
-
"@owlmeans/
|
|
53
|
-
"@owlmeans/oidc": "^0.1.
|
|
54
|
-
"@owlmeans/resource": "^0.1.
|
|
55
|
-
"@owlmeans/route": "^0.1.
|
|
56
|
-
"@owlmeans/server-api": "^0.1.
|
|
57
|
-
"@owlmeans/server-auth": "^0.1.
|
|
58
|
-
"@owlmeans/server-context": "^0.1.
|
|
59
|
-
"@owlmeans/server-
|
|
49
|
+
"@owlmeans/auth": "^0.1.3",
|
|
50
|
+
"@owlmeans/auth-common": "^0.1.3",
|
|
51
|
+
"@owlmeans/basic-envelope": "^0.1.3",
|
|
52
|
+
"@owlmeans/client-entrypoint": "^0.1.3",
|
|
53
|
+
"@owlmeans/config": "^0.1.3",
|
|
54
|
+
"@owlmeans/context": "^0.1.3",
|
|
55
|
+
"@owlmeans/did": "^0.1.3",
|
|
56
|
+
"@owlmeans/entrypoint": "^0.1.3",
|
|
57
|
+
"@owlmeans/oidc": "^0.1.3",
|
|
58
|
+
"@owlmeans/resource": "^0.1.3",
|
|
59
|
+
"@owlmeans/route": "^0.1.3",
|
|
60
|
+
"@owlmeans/server-api": "^0.1.3",
|
|
61
|
+
"@owlmeans/server-auth": "^0.1.3",
|
|
62
|
+
"@owlmeans/server-context": "^0.1.3",
|
|
63
|
+
"@owlmeans/server-entrypoint": "^0.1.3",
|
|
60
64
|
"@scure/base": "^1.1.9",
|
|
61
65
|
"dayjs": "^1.11.13",
|
|
62
|
-
"jose": "
|
|
63
|
-
"openid-client": "
|
|
66
|
+
"jose": "6.2.3",
|
|
67
|
+
"openid-client": "6.8.4"
|
|
64
68
|
},
|
|
65
69
|
"peerDependencies": {
|
|
66
70
|
"ajv": "*"
|
package/src/actions/init.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { RefedEntrypointHandler } from '@owlmeans/server-entrypoint'
|
|
2
2
|
import { handleBody } from '@owlmeans/server-api'
|
|
3
3
|
import type { OIDCAuthInitParams, OidcProviderDescriptor } from '@owlmeans/oidc'
|
|
4
4
|
import { AuthenPayloadError, AuthUnknown, DISPATCHER } from '@owlmeans/auth'
|
|
5
5
|
import { assertContext } from '@owlmeans/context'
|
|
6
6
|
import type { Config, Context, OidcClientAdapter, OidcClientService } from '../types.js'
|
|
7
|
-
import type {
|
|
7
|
+
import type { ClientEntrypoint } from '@owlmeans/client-entrypoint'
|
|
8
8
|
import { authService, DEFAULT_ALIAS } from '../consts.js'
|
|
9
9
|
// import { PROVIDER_CACHE_TTL } from '../consts.js'
|
|
10
10
|
// import type { Client } from 'openid-client'
|
|
@@ -15,7 +15,7 @@ import { sha256 } from '@noble/hashes/sha2'
|
|
|
15
15
|
import { cache, verifierId } from '../utils/cache.js'
|
|
16
16
|
import { AUTHEN_TIMEFRAME } from '@owlmeans/server-auth'
|
|
17
17
|
|
|
18
|
-
export const init:
|
|
18
|
+
export const init: RefedEntrypointHandler = handleBody(async (body: OIDCAuthInitParams, ctx) => {
|
|
19
19
|
if (body.entity == null) {
|
|
20
20
|
throw new AuthenPayloadError('entity')
|
|
21
21
|
}
|
|
@@ -37,7 +37,7 @@ export const init: RefedModuleHandler = handleBody(async (body: OIDCAuthInitPara
|
|
|
37
37
|
* @TODO We need to move it to some remote resource.
|
|
38
38
|
* And make oidc service itself use such a resource to get required client.
|
|
39
39
|
*/
|
|
40
|
-
const [providers] = await context.
|
|
40
|
+
const [providers] = await context.entrypoint<ClientEntrypoint<OidcProviderDescriptor[]>>(
|
|
41
41
|
authService.provider.list
|
|
42
42
|
).call({
|
|
43
43
|
params: { service: context.cfg.alias ?? context.cfg.service },
|
|
@@ -85,7 +85,7 @@ export const init: RefedModuleHandler = handleBody(async (body: OIDCAuthInitPara
|
|
|
85
85
|
entityId,
|
|
86
86
|
}, { ttl: AUTHEN_TIMEFRAME / 1000 })
|
|
87
87
|
|
|
88
|
-
const [dispatcherUrl] = await context.
|
|
88
|
+
const [dispatcherUrl] = await context.entrypoint<ClientEntrypoint<string>>(DISPATCHER).call()
|
|
89
89
|
|
|
90
90
|
const cfg = client.getConfig()
|
|
91
91
|
const url = client.makeAuthUrl({
|
package/src/actions/process.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { RefedEntrypointHandler } from '@owlmeans/server-entrypoint'
|
|
2
2
|
import { handleBody } from '@owlmeans/server-api'
|
|
3
3
|
import type { OIDCClientAuthPayload } from '@owlmeans/oidc'
|
|
4
4
|
import { OIDC_WRAPPED_TOKEN } from '@owlmeans/oidc'
|
|
@@ -30,7 +30,7 @@ import { wrapper } from '../utils/wrapped.js'
|
|
|
30
30
|
*
|
|
31
31
|
* ! There is also token renewal mechanism that should be implemented nearby.
|
|
32
32
|
*/
|
|
33
|
-
export const authenticate:
|
|
33
|
+
export const authenticate: RefedEntrypointHandler = handleBody(async (
|
|
34
34
|
{ authUrl, ...params }: OIDCClientAuthPayload,
|
|
35
35
|
ctx
|
|
36
36
|
) => {
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
|
|
2
|
+
import type { AuthPlugin } from '@owlmeans/server-auth/manager/plugins'
|
|
3
|
+
import { assertType } from '@owlmeans/server-auth/manager/plugins'
|
|
4
|
+
import type { Config, Context, OidcClientService } from '../../types.js'
|
|
5
|
+
import { GOOGLE_CLIENT_AUTH, GOOGLE_SERVICE } from '@owlmeans/oidc'
|
|
6
|
+
import type { OidcProviderDescriptor, ProviderProfileDetails } from '@owlmeans/oidc'
|
|
7
|
+
import { base64urlnopad as base64 } from '@scure/base'
|
|
8
|
+
import { randomBytes } from '@noble/hashes/utils'
|
|
9
|
+
import { sha256 } from '@noble/hashes/sha256'
|
|
10
|
+
import { ALL_SCOPES, AuthenFailed, AuthenPayloadError, AuthManagerError, AuthRole } from '@owlmeans/auth'
|
|
11
|
+
import { AUTHEN_TIMEFRAME } from '@owlmeans/server-auth'
|
|
12
|
+
import { cache, verifierId, exchangeId } from '../../utils/cache.js'
|
|
13
|
+
import type { AccountLinkingService } from '../../types.js'
|
|
14
|
+
import { DEFAULT_ALIAS } from '../../consts.js'
|
|
15
|
+
|
|
16
|
+
const GOOGLE_AUTH_ENDPOINT = 'https://accounts.google.com/o/oauth2/v2/auth'
|
|
17
|
+
const GOOGLE_TOKEN_ENDPOINT = 'https://oauth2.googleapis.com/token'
|
|
18
|
+
const GOOGLE_USERINFO_ENDPOINT = 'https://www.googleapis.com/oauth2/v3/userinfo'
|
|
19
|
+
|
|
20
|
+
export const googleClientPlugin = <C extends Config, T extends Context<C>>(context: T, service: string = GOOGLE_SERVICE): AuthPlugin => {
|
|
21
|
+
const getGoogleConfig = async (): Promise<Required<Pick<OidcProviderDescriptor, 'clientId' | 'secret'>> & OidcProviderDescriptor> => {
|
|
22
|
+
const oidc = context.service<OidcClientService>(DEFAULT_ALIAS)
|
|
23
|
+
const cfg = await oidc.getConfig({ service })
|
|
24
|
+
if (cfg == null || cfg.clientId == null || cfg.secret == null) {
|
|
25
|
+
throw new AuthManagerError('google.config')
|
|
26
|
+
}
|
|
27
|
+
return cfg as Required<Pick<OidcProviderDescriptor, 'clientId' | 'secret'>> & OidcProviderDescriptor
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const plugin: AuthPlugin = {
|
|
31
|
+
type: GOOGLE_CLIENT_AUTH,
|
|
32
|
+
|
|
33
|
+
init: async request => {
|
|
34
|
+
assertType(request.type, plugin)
|
|
35
|
+
|
|
36
|
+
const google = await getGoogleConfig()
|
|
37
|
+
|
|
38
|
+
if (request.source == null) {
|
|
39
|
+
throw new AuthenPayloadError('redirect-uri')
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const verifier = base64.encode(randomBytes(32))
|
|
43
|
+
const challenge = base64.encode(sha256(verifier))
|
|
44
|
+
// Use a random state for cache lookup on callback
|
|
45
|
+
const state = base64.encode(randomBytes(16))
|
|
46
|
+
|
|
47
|
+
await cache<C, T>(context).create({
|
|
48
|
+
id: verifierId(state),
|
|
49
|
+
verifier,
|
|
50
|
+
client: google.clientId,
|
|
51
|
+
redirectUri: request.source,
|
|
52
|
+
}, { ttl: AUTHEN_TIMEFRAME / 1000 })
|
|
53
|
+
|
|
54
|
+
const scopes = google.extraScopes ?? 'openid profile email'
|
|
55
|
+
const authEndpoint = google.authEndpoint ?? GOOGLE_AUTH_ENDPOINT
|
|
56
|
+
|
|
57
|
+
// Use request.source as redirect_uri — it's the browser's current auth page URL
|
|
58
|
+
const params = new URLSearchParams({
|
|
59
|
+
client_id: google.clientId,
|
|
60
|
+
redirect_uri: request.source,
|
|
61
|
+
response_type: 'code',
|
|
62
|
+
scope: scopes,
|
|
63
|
+
code_challenge: challenge,
|
|
64
|
+
code_challenge_method: 'S256',
|
|
65
|
+
state,
|
|
66
|
+
access_type: 'offline',
|
|
67
|
+
prompt: 'consent',
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
const url = `${authEndpoint}?${params.toString()}`
|
|
71
|
+
|
|
72
|
+
return { challenge: url }
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
authenticate: async credential => {
|
|
76
|
+
const google = await getGoogleConfig()
|
|
77
|
+
|
|
78
|
+
// credential.credential contains the query params from Google callback
|
|
79
|
+
const callbackParams = new URLSearchParams(credential.credential)
|
|
80
|
+
const code = callbackParams.get('code')
|
|
81
|
+
const state = callbackParams.get('state')
|
|
82
|
+
|
|
83
|
+
if (code == null) {
|
|
84
|
+
throw new AuthenPayloadError('code')
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (state == null || state === '') {
|
|
88
|
+
throw new AuthenPayloadError('state')
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Look up the PKCE verifier using the state parameter
|
|
92
|
+
const verification = await cache<C, T>(context).pick(verifierId(state))
|
|
93
|
+
if (verification == null || verification.verifier == null) {
|
|
94
|
+
throw new AuthenFailed()
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Use the redirect_uri stored during init for token exchange
|
|
98
|
+
const redirectUri = verification.redirectUri
|
|
99
|
+
if (redirectUri == null) {
|
|
100
|
+
throw new AuthenFailed()
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Exchange code for tokens
|
|
104
|
+
const tokenEndpoint = google.tokenEndpoint ?? GOOGLE_TOKEN_ENDPOINT
|
|
105
|
+
const tokenResponse = await fetch(tokenEndpoint, {
|
|
106
|
+
method: 'POST',
|
|
107
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
108
|
+
body: new URLSearchParams({
|
|
109
|
+
code,
|
|
110
|
+
client_id: google.clientId,
|
|
111
|
+
client_secret: google.secret,
|
|
112
|
+
redirect_uri: redirectUri,
|
|
113
|
+
grant_type: 'authorization_code',
|
|
114
|
+
code_verifier: verification.verifier,
|
|
115
|
+
}),
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
if (!tokenResponse.ok) {
|
|
119
|
+
throw new AuthenFailed()
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const tokens = await tokenResponse.json() as Record<string, string | number | undefined>
|
|
123
|
+
if (tokens.access_token == null) {
|
|
124
|
+
throw new AuthenFailed()
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Fetch user info
|
|
128
|
+
const userinfoEndpoint = google.userinfoEndpoint ?? GOOGLE_USERINFO_ENDPOINT
|
|
129
|
+
const userinfoResponse = await fetch(userinfoEndpoint, {
|
|
130
|
+
headers: { Authorization: `Bearer ${tokens.access_token}` },
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
if (!userinfoResponse.ok) {
|
|
134
|
+
throw new AuthenFailed()
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const userinfo = await userinfoResponse.json() as {
|
|
138
|
+
sub: string; email: string; name?: string; picture?: string
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (userinfo.sub == null || userinfo.email == null) {
|
|
142
|
+
throw new AuthenFailed()
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Use the account linking service to load or create identity
|
|
146
|
+
const oidc = context.service<OidcClientService>(DEFAULT_ALIAS)
|
|
147
|
+
const store = oidc.accountLinking() as AccountLinkingService | null
|
|
148
|
+
if (store == null) {
|
|
149
|
+
throw new AuthManagerError('google.account.store')
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const profileDetails: ProviderProfileDetails = {
|
|
153
|
+
type: GOOGLE_CLIENT_AUTH,
|
|
154
|
+
service,
|
|
155
|
+
clientId: google.clientId,
|
|
156
|
+
userId: userinfo.sub,
|
|
157
|
+
username: userinfo.name ?? userinfo.email,
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
let profile = await store.getLinkedProfile(profileDetails)
|
|
161
|
+
|
|
162
|
+
if (profile == null) {
|
|
163
|
+
profile = await store.linkProfile(profileDetails, {
|
|
164
|
+
username: userinfo.email,
|
|
165
|
+
force: false,
|
|
166
|
+
})
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Generate exchange token for the auth manager to issue final bearer
|
|
170
|
+
const exchangeToken = base64.encode(randomBytes(32))
|
|
171
|
+
await cache<C, T>(context).create(
|
|
172
|
+
{ id: exchangeId(exchangeToken), payload: tokens as any },
|
|
173
|
+
{ ttl: AUTHEN_TIMEFRAME / 1000 }
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
credential.scopes = [ALL_SCOPES]
|
|
177
|
+
credential.source = google.clientId
|
|
178
|
+
credential.role = AuthRole.User
|
|
179
|
+
credential.type = GOOGLE_CLIENT_AUTH
|
|
180
|
+
credential.userId = profile.userId
|
|
181
|
+
credential.profileId = profile.profileId
|
|
182
|
+
credential.entityId = profile.entityId
|
|
183
|
+
|
|
184
|
+
return { token: exchangeToken }
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return plugin
|
|
189
|
+
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
|
|
2
2
|
import { plugins as authPlugins } from '@owlmeans/server-auth/manager'
|
|
3
3
|
import { oidcClientPlugin } from './oidc-client.js'
|
|
4
|
-
import {
|
|
4
|
+
import { googleClientPlugin } from './google-client.js'
|
|
5
|
+
import { OIDC_CLIENT_AUTH, GOOGLE_CLIENT_AUTH } from '@owlmeans/oidc'
|
|
5
6
|
|
|
6
7
|
authPlugins[OIDC_CLIENT_AUTH] = oidcClientPlugin as typeof authPlugins[keyof typeof authPlugins]
|
|
8
|
+
authPlugins[GOOGLE_CLIENT_AUTH] = googleClientPlugin as typeof authPlugins[keyof typeof authPlugins]
|
|
7
9
|
|
|
8
10
|
export const plugins = authPlugins
|
package/src/gate.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createLazyService } from '@owlmeans/context'
|
|
2
|
-
import type { GateService } from '@owlmeans/
|
|
2
|
+
import type { GateService } from '@owlmeans/entrypoint'
|
|
3
3
|
import { OIDC_GATE } from '@owlmeans/oidc'
|
|
4
4
|
import type { Config, Context } from './types.js'
|
|
5
5
|
import { AuthForbidden } from '@owlmeans/auth'
|
package/src/guard.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { OidcGuardOptions } from '@owlmeans/oidc'
|
|
2
2
|
import type { Config, Context } from './types.js'
|
|
3
|
-
import type {
|
|
3
|
+
import type { CommonEntrypoint } from '@owlmeans/entrypoint'
|
|
4
4
|
import {
|
|
5
5
|
appendOidcGuard as appendBasicOidcGuard,
|
|
6
6
|
setupOidcGuard as setupBasicOidcGuard,
|
|
7
7
|
DISPATCHER_OIDC, DISPATCHER_OIDC_INIT
|
|
8
8
|
} from '@owlmeans/oidc'
|
|
9
|
-
import { elevate } from '@owlmeans/server-
|
|
9
|
+
import { elevate } from '@owlmeans/server-entrypoint'
|
|
10
10
|
import * as actions from './actions/index.js'
|
|
11
11
|
|
|
12
12
|
export const appendOidcGuard = <C extends Config, T extends Context<C>>(
|
|
@@ -17,7 +17,7 @@ export const appendOidcGuard = <C extends Config, T extends Context<C>>(
|
|
|
17
17
|
return ctx
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
export const setupOidcGuard = (modules:
|
|
20
|
+
export const setupOidcGuard = (modules: CommonEntrypoint[], coguards?: string | string[]) => {
|
|
21
21
|
setupBasicOidcGuard(modules, coguards)
|
|
22
22
|
|
|
23
23
|
elevate(modules, DISPATCHER_OIDC_INIT, actions.init)
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,20 @@
|
|
|
1
|
-
|
|
1
|
+
// Public types — no upstream openid-client types re-exported
|
|
2
|
+
export type {
|
|
3
|
+
OidcClientDescriptor,
|
|
4
|
+
OidcTokenSet,
|
|
5
|
+
OidcTokenSetParameters,
|
|
6
|
+
OidcGrantChecks,
|
|
7
|
+
OidcServerMetadata,
|
|
8
|
+
OidcIntrospectionResponse,
|
|
9
|
+
OidcClientService,
|
|
10
|
+
OidcClientAdapter,
|
|
11
|
+
OidcRpConfig,
|
|
12
|
+
Config,
|
|
13
|
+
Context,
|
|
14
|
+
AccountLinkingService,
|
|
15
|
+
AccountMeta,
|
|
16
|
+
ProviderApiService,
|
|
17
|
+
} from './types.js'
|
|
2
18
|
export * from './consts.js'
|
|
3
19
|
export * from './service.js'
|
|
4
20
|
export * from './guard.js'
|
package/src/model/gate.ts
CHANGED
|
@@ -4,7 +4,7 @@ import type { Config, Context, OidcClientService } from '../types.js'
|
|
|
4
4
|
import { cache, managedId } from '../utils/cache.js'
|
|
5
5
|
import type { GateModel, PermissionRequest, PermissionResponse } from './types.js'
|
|
6
6
|
import { ResponseMode } from './consts.js'
|
|
7
|
-
import type {
|
|
7
|
+
import type { ClientEntrypoint } from '@owlmeans/client-entrypoint'
|
|
8
8
|
import type { OidcProviderDescriptor } from '@owlmeans/oidc'
|
|
9
9
|
|
|
10
10
|
export const createGateModel = <C extends Config, T extends Context<C>>(ctx: T): GateModel => {
|
|
@@ -18,7 +18,7 @@ export const createGateModel = <C extends Config, T extends Context<C>>(ctx: T):
|
|
|
18
18
|
})
|
|
19
19
|
} catch (e) {
|
|
20
20
|
if (e instanceof AuthManagerError) {
|
|
21
|
-
const [providers] = await ctx.
|
|
21
|
+
const [providers] = await ctx.entrypoint<ClientEntrypoint<OidcProviderDescriptor[]>>(
|
|
22
22
|
authService.provider.list
|
|
23
23
|
).call({
|
|
24
24
|
params: { service: ctx.cfg.alias ?? ctx.cfg.service },
|
package/src/modules.ts
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import {
|
|
1
|
+
import type { CommonEntrypoint } from '@owlmeans/entrypoint'
|
|
2
|
+
import { entrypoint, guard, filter, body } from '@owlmeans/entrypoint'
|
|
3
3
|
import { backend, route, RouteMethod, service } from '@owlmeans/route'
|
|
4
4
|
import { authService } from './consts.js'
|
|
5
|
-
import { elevate } from '@owlmeans/client-
|
|
5
|
+
import { elevate } from '@owlmeans/client-entrypoint'
|
|
6
6
|
import { GUARD_ED25519 } from '@owlmeans/auth-common'
|
|
7
7
|
import { OIDCTokenUpdateSchema } from '@owlmeans/oidc'
|
|
8
8
|
|
|
9
9
|
export const setupAuthServiceModules = (
|
|
10
|
-
modules:
|
|
10
|
+
modules: CommonEntrypoint[],
|
|
11
11
|
serviceAlias: string,
|
|
12
12
|
prefix: string = 'oidc-api'
|
|
13
13
|
) => {
|
|
14
14
|
modules.push(
|
|
15
|
-
|
|
15
|
+
entrypoint(
|
|
16
16
|
route(authService.provider.list, `/${prefix}/provider/:service`, service(serviceAlias)),
|
|
17
17
|
guard(GUARD_ED25519)
|
|
18
18
|
),
|
|
19
|
-
|
|
19
|
+
entrypoint(
|
|
20
20
|
route(
|
|
21
21
|
authService.auth.update, `/${prefix}/auth/update`,
|
|
22
22
|
backend(service(serviceAlias), RouteMethod.POST)
|
package/src/service.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { DEF_OIDC_ACCOUNT_LINKING, DEF_OIDC_PROVIDER_API, DEFAULT_ALIAS } from './consts.js'
|
|
2
2
|
import { assertContext, createService } from '@owlmeans/context'
|
|
3
|
-
import type { AccountLinkingService, Config, Context, OidcClientService, ProviderApiService, OidcClientAdapter } from './types.js'
|
|
3
|
+
import type { AccountLinkingService, Config, Context, OidcClientService, ProviderApiService, OidcClientAdapter, OidcTokenSet, OidcTokenSetParameters, OidcIntrospectionResponse } from './types.js'
|
|
4
|
+
import type { AuthorizationCodeGrantChecks } from 'openid-client'
|
|
4
5
|
import { AuthManagerError } from '@owlmeans/auth'
|
|
5
6
|
import { makeSecurityHelper } from '@owlmeans/config'
|
|
6
7
|
import * as client from 'openid-client'
|
|
@@ -22,7 +23,7 @@ export const makeOidcClientService = (alias: string = DEFAULT_ALIAS): OidcClient
|
|
|
22
23
|
throw new AuthManagerError('oidc.client.service')
|
|
23
24
|
}
|
|
24
25
|
|
|
25
|
-
if (typeof clientId === 'object' && clientId.clientId == null) {
|
|
26
|
+
if (typeof clientId === 'object' && clientId.clientId == null && cfg.clientId == null) {
|
|
26
27
|
throw new AuthManagerError('oidc.client.client-id')
|
|
27
28
|
}
|
|
28
29
|
|
|
@@ -82,8 +83,8 @@ export const makeOidcClientService = (alias: string = DEFAULT_ALIAS): OidcClient
|
|
|
82
83
|
|
|
83
84
|
makeAuthUrl: params => client.buildAuthorizationUrl(descriptor, params).toString(),
|
|
84
85
|
|
|
85
|
-
|
|
86
|
-
|
|
86
|
+
grantWithCredentials: async () =>
|
|
87
|
+
client.clientCredentialsGrant(descriptor) as Promise<OidcTokenSet>,
|
|
87
88
|
|
|
88
89
|
grantWithCode: async (url, checks, params) => {
|
|
89
90
|
const urlObj = new URL(url)
|
|
@@ -97,9 +98,9 @@ export const makeOidcClientService = (alias: string = DEFAULT_ALIAS): OidcClient
|
|
|
97
98
|
|
|
98
99
|
checks.idTokenExpected ??= true
|
|
99
100
|
|
|
100
|
-
return
|
|
101
|
-
descriptor, urlObj, checks
|
|
102
|
-
)
|
|
101
|
+
return client.authorizationCodeGrant(
|
|
102
|
+
descriptor, urlObj, checks as AuthorizationCodeGrantChecks
|
|
103
|
+
) as Promise<OidcTokenSet>
|
|
103
104
|
},
|
|
104
105
|
|
|
105
106
|
refresh: async tokenSet => {
|
|
@@ -107,11 +108,15 @@ export const makeOidcClientService = (alias: string = DEFAULT_ALIAS): OidcClient
|
|
|
107
108
|
if (refreshToken == null) {
|
|
108
109
|
throw new AuthManagerError('refresh-token')
|
|
109
110
|
}
|
|
110
|
-
return
|
|
111
|
+
return client.refreshTokenGrant(descriptor, refreshToken) as Promise<OidcTokenSetParameters>
|
|
111
112
|
},
|
|
112
113
|
|
|
113
|
-
introspect: async (tokenSet, type = 'access_token') =>
|
|
114
|
-
|
|
114
|
+
introspect: async (tokenSet, type = 'access_token') => {
|
|
115
|
+
const tokenValue = type === 'refresh_token' ? tokenSet.refresh_token
|
|
116
|
+
: type === 'id_token' ? tokenSet.id_token
|
|
117
|
+
: tokenSet.access_token
|
|
118
|
+
return client.tokenIntrospection(descriptor, tokenValue as string) as Promise<OidcIntrospectionResponse>
|
|
119
|
+
},
|
|
115
120
|
|
|
116
121
|
} satisfies OidcClientAdapter
|
|
117
122
|
},
|
|
@@ -119,7 +124,7 @@ export const makeOidcClientService = (alias: string = DEFAULT_ALIAS): OidcClient
|
|
|
119
124
|
getConfig: async clientId => {
|
|
120
125
|
const context = assertContext<Config, Context>(service.ctx as Context, alias)
|
|
121
126
|
|
|
122
|
-
if (typeof clientId === 'object' && clientId.clientId == null) {
|
|
127
|
+
if (typeof clientId === 'object' && clientId.clientId == null && clientId.service == null) {
|
|
123
128
|
throw new AuthManagerError('oidc.client.client-id')
|
|
124
129
|
}
|
|
125
130
|
|
|
@@ -128,7 +133,7 @@ export const makeOidcClientService = (alias: string = DEFAULT_ALIAS): OidcClient
|
|
|
128
133
|
return consumer.clientId === clientId
|
|
129
134
|
}
|
|
130
135
|
return Object.entries(clientId).every(
|
|
131
|
-
([key, value]) => consumer[key as keyof typeof consumer] === value
|
|
136
|
+
([key, value]) => value == null || consumer[key as keyof typeof consumer] === value
|
|
132
137
|
)
|
|
133
138
|
})
|
|
134
139
|
},
|
|
@@ -159,6 +164,11 @@ export const makeOidcClientService = (alias: string = DEFAULT_ALIAS): OidcClient
|
|
|
159
164
|
return null
|
|
160
165
|
},
|
|
161
166
|
|
|
167
|
+
findProvider: predicate => {
|
|
168
|
+
const context = assertContext<Config, Context>(service.ctx as Context, alias)
|
|
169
|
+
return (context.cfg.oidc.providers ?? []).find(predicate)
|
|
170
|
+
},
|
|
171
|
+
|
|
162
172
|
hasProvider: params => {
|
|
163
173
|
const ctx = service.assertCtx<Config, Context>()
|
|
164
174
|
if (ctx.cfg.oidc.providers == null) {
|
package/src/types.ts
CHANGED
|
@@ -1,13 +1,70 @@
|
|
|
1
1
|
import type { InitializedService } from '@owlmeans/context'
|
|
2
|
-
import type { AuthorizationCodeGrantChecks, Configuration, IntrospectionResponse, ServerMetadata, TokenEndpointResponse, TokenEndpointResponseHelpers } from 'openid-client'
|
|
3
2
|
import type { ServerConfig, ServerContext } from '@owlmeans/server-context'
|
|
4
3
|
import type { OidcProviderConfig, OidcSharedConfig, WithSharedConfig, ProviderProfileDetails, OidcUserDetails, OidcProviderSettings } from '@owlmeans/oidc'
|
|
5
4
|
import type { AuthCredentials, AuthPayload, Profile } from '@owlmeans/auth'
|
|
5
|
+
import type { Configuration, ServerMetadata, TokenEndpointResponse, TokenEndpointResponseHelpers } from 'openid-client'
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
// OwlMeans-owned public types — no upstream openid-client type appears below
|
|
9
|
+
// the line marked with (@public). Only src/service.ts may import openid-client
|
|
10
|
+
// types directly; all other files use these interfaces.
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
|
|
13
|
+
/** Opaque descriptor for an OIDC client configuration obtained via discovery.
|
|
14
|
+
* Consumers receive and pass it back; they must never read its internals. */
|
|
15
|
+
export type OidcClientDescriptor = Configuration
|
|
16
|
+
|
|
17
|
+
/** Token set returned from any grant. Includes the standard OAuth2 fields
|
|
18
|
+
* plus the openid-client helper method `claims()` for ID-token claim access. */
|
|
19
|
+
export interface OidcTokenSet {
|
|
20
|
+
access_token?: string
|
|
21
|
+
refresh_token?: string
|
|
22
|
+
id_token?: string
|
|
23
|
+
token_type?: string
|
|
24
|
+
expires_in?: number
|
|
25
|
+
scope?: string
|
|
26
|
+
/** Decode and return claims from the ID token. */
|
|
27
|
+
claims: () => Record<string, unknown>
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Subset of OidcTokenSet without helper methods; used for storage/serialization. */
|
|
31
|
+
export type OidcTokenSetParameters = Pick<OidcTokenSet, 'access_token' | 'refresh_token' | 'id_token' | 'token_type' | 'expires_in' | 'scope'>
|
|
32
|
+
|
|
33
|
+
/** PKCE + ID-token check parameters for the authorization-code grant. */
|
|
34
|
+
export interface OidcGrantChecks {
|
|
35
|
+
pkceCodeVerifier?: string
|
|
36
|
+
idTokenExpected?: boolean
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Issuer/endpoint metadata from the OIDC discovery document. */
|
|
40
|
+
export type OidcServerMetadata = ServerMetadata
|
|
41
|
+
|
|
42
|
+
/** Response from token introspection. */
|
|
43
|
+
export interface OidcIntrospectionResponse {
|
|
44
|
+
active: boolean
|
|
45
|
+
scope?: string
|
|
46
|
+
sub?: string
|
|
47
|
+
client_id?: string
|
|
48
|
+
token_type?: string
|
|
49
|
+
exp?: number
|
|
50
|
+
iat?: number
|
|
51
|
+
[key: string]: unknown
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
// Internal adapter types — used only within this package (@internal)
|
|
56
|
+
// These preserve the upstream types for internal implementation use only.
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
|
|
59
|
+
/** @internal — internal alias; do not export from index.ts */
|
|
8
60
|
export type TokenSet = TokenEndpointResponse & TokenEndpointResponseHelpers
|
|
61
|
+
/** @internal */
|
|
9
62
|
export type TokenSetParameters = TokenEndpointResponse
|
|
10
63
|
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
// Service interfaces (@public)
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
|
|
11
68
|
export interface OidcClientService extends InitializedService {
|
|
12
69
|
getConfiguration: (clientId: string | Partial<OidcProviderConfig>) => Promise<OidcClientDescriptor>
|
|
13
70
|
getClient: (clientId: string | OidcClientDescriptor | Partial<OidcProviderConfig>) => Promise<OidcClientAdapter>
|
|
@@ -16,22 +73,23 @@ export interface OidcClientService extends InitializedService {
|
|
|
16
73
|
|
|
17
74
|
registerTemporaryProvider: (config: OidcProviderConfig) => OidcProviderConfig
|
|
18
75
|
unregisterTemporaryProvider: (params: Partial<OidcProviderConfig>) => void
|
|
19
|
-
hasProvider: (params: Partial<OidcProviderConfig>) => boolean
|
|
76
|
+
hasProvider: (params: string | Partial<OidcProviderConfig>) => boolean
|
|
20
77
|
entityToClientId: (params: Partial<OidcProviderConfig>) => string
|
|
21
78
|
|
|
22
79
|
providerApi: () => ProviderApiService | null
|
|
23
80
|
accountLinking: () => AccountLinkingService | null
|
|
81
|
+
findProvider: (predicate: (provider: OidcProviderConfig) => boolean) => OidcProviderConfig | undefined
|
|
24
82
|
}
|
|
25
83
|
|
|
26
84
|
export interface OidcClientAdapter {
|
|
27
|
-
getMetadata: () =>
|
|
85
|
+
getMetadata: () => OidcServerMetadata
|
|
28
86
|
getClientId: () => string
|
|
29
87
|
getConfig: () => OidcProviderConfig
|
|
30
88
|
makeAuthUrl: (params: Record<string, string>) => string
|
|
31
|
-
grantWithCredentials: () => Promise<
|
|
32
|
-
grantWithCode: (currentUrl: string, checks:
|
|
33
|
-
refresh: (tokenSet:
|
|
34
|
-
introspect: (tokenSet:
|
|
89
|
+
grantWithCredentials: () => Promise<OidcTokenSet>
|
|
90
|
+
grantWithCode: (currentUrl: string, checks: OidcGrantChecks, params: Record<string, string>) => Promise<OidcTokenSet>
|
|
91
|
+
refresh: (tokenSet: OidcTokenSetParameters | string) => Promise<OidcTokenSetParameters>
|
|
92
|
+
introspect: (tokenSet: OidcTokenSetParameters, type?: string) => Promise<OidcIntrospectionResponse>
|
|
35
93
|
}
|
|
36
94
|
|
|
37
95
|
export interface OidcRpConfig extends OidcSharedConfig {
|
|
@@ -62,3 +120,4 @@ export interface ProviderApiService extends InitializedService {
|
|
|
62
120
|
getUserDetails: (token: string, userId: string) => Promise<OidcUserDetails>
|
|
63
121
|
getSettings: (token: string, realm: string) => Promise<OidcProviderSettings>
|
|
64
122
|
}
|
|
123
|
+
|