@geexcode/geex-extensions-authentication 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { signal, InjectionToken, makeEnvironmentProviders, importProvidersFrom } from '@angular/core';
|
|
2
|
+
import { gql, Apollo } from 'apollo-angular';
|
|
3
|
+
import { OAuthService, OAuthStorage, OAuthModule } from 'angular-oauth2-oidc';
|
|
4
|
+
import { firstValueFrom, map } from 'rxjs';
|
|
5
|
+
import { guardedSignal, GEEX_LOGIN_PATH, provideGeexModuleContribution } from '@geexcode/geex-angular';
|
|
6
|
+
|
|
7
|
+
const GQL_FEDERATE_AUTH = gql `mutation federateAuthenticate(
|
|
8
|
+
$code: String!
|
|
9
|
+
$loginProvider: LoginProviderEnum!
|
|
10
|
+
) {
|
|
11
|
+
federateAuthenticate(
|
|
12
|
+
request: { code: $code, loginProvider: $loginProvider }
|
|
13
|
+
) {
|
|
14
|
+
token
|
|
15
|
+
loginProvider
|
|
16
|
+
userId
|
|
17
|
+
name
|
|
18
|
+
user {
|
|
19
|
+
id
|
|
20
|
+
username
|
|
21
|
+
nickname
|
|
22
|
+
phoneNumber
|
|
23
|
+
email
|
|
24
|
+
isEnable
|
|
25
|
+
createdOn
|
|
26
|
+
... on IUser {
|
|
27
|
+
roleNames
|
|
28
|
+
roleIds
|
|
29
|
+
permissions
|
|
30
|
+
orgCodes
|
|
31
|
+
avatarFileId
|
|
32
|
+
orgs {
|
|
33
|
+
allParentOrgs {
|
|
34
|
+
code
|
|
35
|
+
name
|
|
36
|
+
}
|
|
37
|
+
name
|
|
38
|
+
code
|
|
39
|
+
}
|
|
40
|
+
claims {
|
|
41
|
+
claimType
|
|
42
|
+
claimValue
|
|
43
|
+
}
|
|
44
|
+
avatarFile {
|
|
45
|
+
id
|
|
46
|
+
createdOn
|
|
47
|
+
fileSize
|
|
48
|
+
mimeType
|
|
49
|
+
storageType
|
|
50
|
+
fileName
|
|
51
|
+
md5
|
|
52
|
+
url
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
`;
|
|
59
|
+
function createAuthenticationModule(injector) {
|
|
60
|
+
const _user = signal(null, ...(ngDevMode ? [{ debugName: "_user" }] : []));
|
|
61
|
+
let _initialized = false;
|
|
62
|
+
let _initPromise = null;
|
|
63
|
+
const runInit = () => {
|
|
64
|
+
_initPromise = (async () => {
|
|
65
|
+
try {
|
|
66
|
+
const userData = await module.loadUserData();
|
|
67
|
+
_user.set(userData ?? null);
|
|
68
|
+
_initialized = true;
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
console.error(err);
|
|
72
|
+
}
|
|
73
|
+
})();
|
|
74
|
+
return _initPromise;
|
|
75
|
+
};
|
|
76
|
+
const module = {
|
|
77
|
+
init: () => {
|
|
78
|
+
if (_initPromise) {
|
|
79
|
+
return _initPromise;
|
|
80
|
+
}
|
|
81
|
+
return runInit();
|
|
82
|
+
},
|
|
83
|
+
reload: () => {
|
|
84
|
+
_initialized = false;
|
|
85
|
+
_initPromise = null;
|
|
86
|
+
return runInit();
|
|
87
|
+
},
|
|
88
|
+
user: guardedSignal(_user, () => _initialized),
|
|
89
|
+
async loadUserData() {
|
|
90
|
+
const oAuthService = injector.get(OAuthService);
|
|
91
|
+
try {
|
|
92
|
+
// Always discover: issuer alignment is required for id_token / userinfo, not only endpoint URLs.
|
|
93
|
+
await oAuthService.loadDiscoveryDocument();
|
|
94
|
+
if (!oAuthService.hasValidAccessToken()) {
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
await oAuthService.loadUserProfile();
|
|
98
|
+
const profile = oAuthService.getIdentityClaims();
|
|
99
|
+
if (!profile?.login_provider) {
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
return await firstValueFrom(injector
|
|
103
|
+
.get(Apollo)
|
|
104
|
+
.mutate({
|
|
105
|
+
mutation: GQL_FEDERATE_AUTH,
|
|
106
|
+
variables: {
|
|
107
|
+
code: oAuthService.getAccessToken(),
|
|
108
|
+
loginProvider: profile.login_provider,
|
|
109
|
+
},
|
|
110
|
+
})
|
|
111
|
+
.pipe(map(res => res?.data?.federateAuthenticate.user)));
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
console.error(err);
|
|
115
|
+
}
|
|
116
|
+
return undefined;
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
return module;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const GEEX_AUTHENTICATION_OPTIONS = new InjectionToken("GEEX_AUTHENTICATION_OPTIONS");
|
|
123
|
+
function provideGeexAuthentication(options = {}) {
|
|
124
|
+
return makeEnvironmentProviders([
|
|
125
|
+
{ provide: GEEX_AUTHENTICATION_OPTIONS, useValue: options },
|
|
126
|
+
...(options.loginPath ? [{ provide: GEEX_LOGIN_PATH, useValue: options.loginPath }] : []),
|
|
127
|
+
{ provide: OAuthStorage, useFactory: options.oauthStorage ?? (() => localStorage) },
|
|
128
|
+
importProvidersFrom(OAuthModule.forRoot()),
|
|
129
|
+
provideGeexModuleContribution({
|
|
130
|
+
createModules: ({ injector }) => ({
|
|
131
|
+
authentication: (options.createAuthenticationModule ?? createAuthenticationModule)(injector),
|
|
132
|
+
}),
|
|
133
|
+
}),
|
|
134
|
+
]);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Generated bundle index. Do not edit.
|
|
139
|
+
*/
|
|
140
|
+
|
|
141
|
+
export { GEEX_AUTHENTICATION_OPTIONS, createAuthenticationModule, provideGeexAuthentication };
|
|
142
|
+
//# sourceMappingURL=geexcode-geex-extensions-authentication.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geexcode-geex-extensions-authentication.mjs","sources":["../../src/authentication.module.ts","../../src/provide-geex-authentication.ts","../../src/geexcode-geex-extensions-authentication.ts"],"sourcesContent":["import { Injector, signal } from \"@angular/core\";\nimport { Apollo, gql } from \"apollo-angular\";\nimport { OAuthService } from \"angular-oauth2-oidc\";\nimport type { User } from \"@geexcode/geex-extensions-identity\";\nimport { firstValueFrom, map } from \"rxjs\";\nimport { guardedSignal } from \"@geexcode/geex-angular\";\nimport type { AuthenticationModule } from \"./authentication.types\";\n\nconst GQL_FEDERATE_AUTH = gql`mutation federateAuthenticate(\n $code: String!\n $loginProvider: LoginProviderEnum!\n) {\n federateAuthenticate(\n request: { code: $code, loginProvider: $loginProvider }\n ) {\n token\n loginProvider\n userId\n name\n user {\n id\n username\n nickname\n phoneNumber\n email\n isEnable\n createdOn\n ... on IUser {\n roleNames\n roleIds\n permissions\n orgCodes\n avatarFileId\n orgs {\n allParentOrgs {\n code\n name\n }\n name\n code\n }\n claims {\n claimType\n claimValue\n }\n avatarFile {\n id\n createdOn\n fileSize\n mimeType\n storageType\n fileName\n md5\n url\n }\n }\n }\n }\n}\n`;\n\nexport function createAuthenticationModule(injector: Injector): AuthenticationModule {\n const _user = signal<User | null>(null);\n let _initialized = false;\n let _initPromise: Promise<void> | null = null;\n\n const runInit = () => {\n _initPromise = (async () => {\n try {\n const userData = await module.loadUserData();\n _user.set(userData ?? null);\n _initialized = true;\n } catch (err) {\n console.error(err);\n }\n })();\n return _initPromise;\n };\n\n const module = {\n init: () => {\n if (_initPromise) {\n return _initPromise;\n }\n return runInit();\n },\n reload: () => {\n _initialized = false;\n _initPromise = null;\n return runInit();\n },\n user: guardedSignal(_user, () => _initialized),\n async loadUserData(): Promise<User | undefined> {\n const oAuthService = injector.get(OAuthService);\n try {\n // Always discover: issuer alignment is required for id_token / userinfo, not only endpoint URLs.\n await oAuthService.loadDiscoveryDocument();\n if (!oAuthService.hasValidAccessToken()) {\n return undefined;\n }\n await oAuthService.loadUserProfile();\n const profile = oAuthService.getIdentityClaims() as { login_provider?: string } | null;\n if (!profile?.login_provider) {\n return undefined;\n }\n type FederateAuthResponse = { federateAuthenticate: { user: User } };\n return await firstValueFrom(\n injector\n .get(Apollo)\n .mutate<FederateAuthResponse>({\n mutation: GQL_FEDERATE_AUTH,\n variables: {\n code: oAuthService.getAccessToken(),\n loginProvider: profile.login_provider,\n },\n })\n .pipe(map(res => res?.data?.federateAuthenticate.user)),\n );\n } catch (err) {\n console.error(err);\n }\n return undefined;\n },\n };\n return module as AuthenticationModule;\n}\n","import {\r\r\n EnvironmentProviders,\r\r\n InjectionToken,\r\r\n Injector,\r\r\n importProvidersFrom,\r\r\n makeEnvironmentProviders,\r\r\n} from \"@angular/core\";\r\r\nimport { GEEX_LOGIN_PATH, provideGeexModuleContribution } from \"@geexcode/geex-angular\";\r\r\nimport { OAuthModule, OAuthStorage } from \"angular-oauth2-oidc\";\r\r\nimport { createAuthenticationModule } from \"./authentication.module\";\r\r\nimport type { AuthenticationModule } from \"./authentication.types\";\r\r\n\r\r\nexport interface GeexAuthenticationOptions {\r\r\n readonly createAuthenticationModule?: (injector: Injector) => AuthenticationModule;\r\r\n readonly loginPath?: string;\r\r\n readonly oauthStorage?: () => OAuthStorage;\r\r\n}\r\r\n\r\r\nexport const GEEX_AUTHENTICATION_OPTIONS = new InjectionToken<Readonly<GeexAuthenticationOptions>>(\r\r\n \"GEEX_AUTHENTICATION_OPTIONS\",\r\r\n);\r\r\n\r\r\nexport function provideGeexAuthentication(\r\r\n options: Readonly<GeexAuthenticationOptions> = {},\r\r\n): EnvironmentProviders {\r\r\n return makeEnvironmentProviders([\r\r\n { provide: GEEX_AUTHENTICATION_OPTIONS, useValue: options },\r\r\n ...(options.loginPath ? [{ provide: GEEX_LOGIN_PATH, useValue: options.loginPath }] : []),\r\r\n { provide: OAuthStorage, useFactory: options.oauthStorage ?? (() => localStorage) },\r\r\n importProvidersFrom(OAuthModule.forRoot()),\r\r\n provideGeexModuleContribution({\r\r\n createModules: ({ injector }) => ({\r\r\n authentication: (options.createAuthenticationModule ?? createAuthenticationModule)(injector),\r\r\n }),\r\r\n }),\r\r\n ]);\r\r\n}\r\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { WritableSignal, Injector, InjectionToken, EnvironmentProviders } from '@angular/core';
|
|
2
|
+
import { GeexModule } from '@geexcode/geex-angular';
|
|
3
|
+
import { User } from '@geexcode/geex-extensions-identity';
|
|
4
|
+
import { OAuthStorage } from 'angular-oauth2-oidc';
|
|
5
|
+
|
|
6
|
+
interface AuthenticationModule extends GeexModule<{
|
|
7
|
+
user: WritableSignal<User | null>;
|
|
8
|
+
loadUserData(): Promise<User | undefined>;
|
|
9
|
+
/** Drop cached session and reload user from the current OAuth access token. */
|
|
10
|
+
reload(): Promise<void>;
|
|
11
|
+
}> {
|
|
12
|
+
}
|
|
13
|
+
declare module "@geexcode/geex-angular" {
|
|
14
|
+
interface GeexModuleMap {
|
|
15
|
+
authentication: AuthenticationModule;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
declare function createAuthenticationModule(injector: Injector): AuthenticationModule;
|
|
20
|
+
|
|
21
|
+
interface GeexAuthenticationOptions {
|
|
22
|
+
readonly createAuthenticationModule?: (injector: Injector) => AuthenticationModule;
|
|
23
|
+
readonly loginPath?: string;
|
|
24
|
+
readonly oauthStorage?: () => OAuthStorage;
|
|
25
|
+
}
|
|
26
|
+
declare const GEEX_AUTHENTICATION_OPTIONS: InjectionToken<Readonly<GeexAuthenticationOptions>>;
|
|
27
|
+
declare function provideGeexAuthentication(options?: Readonly<GeexAuthenticationOptions>): EnvironmentProviders;
|
|
28
|
+
|
|
29
|
+
export { GEEX_AUTHENTICATION_OPTIONS, createAuthenticationModule, provideGeexAuthentication };
|
|
30
|
+
export type { AuthenticationModule, GeexAuthenticationOptions };
|
|
31
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sources":["../src/authentication.types.ts","../src/authentication.module.ts","../src/provide-geex-authentication.ts"],"mappings":";;;;;AAIA,UAAM,oBAAW,SAAqB,UAAQ;AAC5C,UAAM,cAAc,CAAC,IAAI;AACzB,oBAAgB,OAAO,CAAC,IAAI;;AAE5B,cAAU,OAAO;;AACd;AAEL;AACE;wBACkB,oBAAoB;AACrC;AACF;;AC8CD,iBAAA,qCAA2C,QAAU,GAAA;;ACrCrD,mCAAiB;qDAEkC,QAAQ,KAAK,oBAAoB;AAElF;AAEA,kCAA8B,YAAY;AAE3C;AAID,cAAA,2BAAa,EAAA,cAA2B,CAAA,QAAA,CAAA,yBAAA;AAQxC,iBAAA,yBAAgB,WAEd,QAAS,CAAA,yBAAS,IAAA,oBAEjB;;;;","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@geexcode/geex-extensions-authentication",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Geex authentication extension: headless OAuth authentication module and domain tokens. Aligns with Geex.Extensions.Authentication.",
|
|
5
|
+
"sideEffects": false,
|
|
6
|
+
"peerDependencies": {
|
|
7
|
+
"@angular/core": "^20.0.0",
|
|
8
|
+
"@geexcode/geex-angular": ">=0.0.41",
|
|
9
|
+
"@geexcode/geex-extensions-identity": ">=0.0.1",
|
|
10
|
+
"angular-oauth2-oidc": ">=15.0.0 <21.0.0",
|
|
11
|
+
"apollo-angular": "^14.0.0",
|
|
12
|
+
"graphql": "^16.8.0",
|
|
13
|
+
"rxjs": "^7.8.0"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"tslib": "^2.6.3"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist"
|
|
20
|
+
],
|
|
21
|
+
"module": "dist/fesm2022/geexcode-geex-extensions-authentication.mjs",
|
|
22
|
+
"typings": "dist/index.d.ts",
|
|
23
|
+
"exports": {
|
|
24
|
+
"./package.json": {
|
|
25
|
+
"default": "./package.json"
|
|
26
|
+
},
|
|
27
|
+
".": {
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"import": "./dist/fesm2022/geexcode-geex-extensions-authentication.mjs",
|
|
30
|
+
"default": "./dist/fesm2022/geexcode-geex-extensions-authentication.mjs"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"scripts": {
|
|
34
|
+
"clean": "rimraf dist",
|
|
35
|
+
"build": "ng-packagr -p ng-package.json -c tsconfig.lib.json",
|
|
36
|
+
"test": "node --test src/provide-geex-authentication.node-test.mjs",
|
|
37
|
+
"prepublishOnly": "npm run build",
|
|
38
|
+
"publish:public": "npm publish ./dist --access public"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@angular/compiler": "^20.0.0",
|
|
42
|
+
"@angular/compiler-cli": "^20.0.0",
|
|
43
|
+
"@angular/core": "^20.0.0",
|
|
44
|
+
"@geexcode/geex-angular": "workspace:*",
|
|
45
|
+
"@geexcode/geex-extensions-identity": "workspace:*",
|
|
46
|
+
"angular-oauth2-oidc": "^20.0.2",
|
|
47
|
+
"apollo-angular": "^14.1.0",
|
|
48
|
+
"graphql": "^16.9.0",
|
|
49
|
+
"ng-packagr": "^20.0.0",
|
|
50
|
+
"rimraf": "^5.0.5",
|
|
51
|
+
"rxjs": "^7.8.2",
|
|
52
|
+
"typescript": "~5.8.3"
|
|
53
|
+
}
|
|
54
|
+
}
|