@tstdl/base 0.93.112 → 0.93.114

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.
@@ -4,13 +4,14 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
+ import { InvalidTokenError } from '../../errors/invalid-token.error.js';
7
8
  import { Singleton } from '../../injector/decorators.js';
8
9
  import { isNull } from '../../utils/type-guards.js';
9
10
  export class ApiRequestTokenProvider {
10
11
  async getToken(data) {
11
12
  const token = await this.tryGetToken(data);
12
13
  if (isNull(token)) {
13
- throw new Error('No token available for request');
14
+ throw new InvalidTokenError('No token available for request');
14
15
  }
15
16
  return token;
16
17
  }
@@ -7,6 +7,12 @@ import type { AuthenticationClientService } from './authentication.service.js';
7
7
  * @returns A http client middleware.
8
8
  */
9
9
  export declare function waitForAuthenticationCredentialsMiddleware(authenticationServiceOrProvider: ValueOrAsyncProvider<AuthenticationClientService>): HttpClientMiddleware;
10
+ /**
11
+ * A http client middleware that logs out the user if a request fails with a 401 Unauthorized error.
12
+ * @param authenticationServiceOrProvider The authentication service or a provider for it.
13
+ * @returns A http client middleware.
14
+ */
15
+ export declare function logoutOnUnauthorizedMiddleware(authenticationServiceOrProvider: ValueOrAsyncProvider<AuthenticationClientService>): HttpClientMiddleware;
10
16
  /**
11
17
  * A http client middleware that adds authentication tokens to outgoing requests and extracts them from incoming responses.
12
18
  * @param authenticationServiceOrProvider The authentication service or a provider for it.
@@ -1,4 +1,5 @@
1
1
  import { firstValueFrom, timeout } from 'rxjs';
2
+ import { HttpError } from '../../http/index.js';
2
3
  import { isDefined } from '../../utils/type-guards.js';
3
4
  import { cacheValueOrAsyncProvider } from '../../utils/value-or-provider.js';
4
5
  import { dontWaitForValidToken } from '../authentication.api.js';
@@ -21,6 +22,27 @@ export function waitForAuthenticationCredentialsMiddleware(authenticationService
21
22
  }
22
23
  return waitForAuthenticationCredentialsMiddleware;
23
24
  }
25
+ /**
26
+ * A http client middleware that logs out the user if a request fails with a 401 Unauthorized error.
27
+ * @param authenticationServiceOrProvider The authentication service or a provider for it.
28
+ * @returns A http client middleware.
29
+ */
30
+ export function logoutOnUnauthorizedMiddleware(authenticationServiceOrProvider) {
31
+ const getAuthenticationService = cacheValueOrAsyncProvider(authenticationServiceOrProvider);
32
+ async function logoutOnUnauthorizedMiddleware(_context, next) {
33
+ try {
34
+ await next();
35
+ }
36
+ catch (error) {
37
+ if ((error instanceof HttpError) && (error.response?.statusCode == 401)) {
38
+ const authenticationService = await getAuthenticationService();
39
+ await authenticationService.logout();
40
+ }
41
+ throw error;
42
+ }
43
+ }
44
+ return logoutOnUnauthorizedMiddleware;
45
+ }
24
46
  /**
25
47
  * A http client middleware that adds authentication tokens to outgoing requests and extracts them from incoming responses.
26
48
  * @param authenticationServiceOrProvider The authentication service or a provider for it.
@@ -3,7 +3,7 @@ import { getCurrentInjector } from '../../injector/inject.js';
3
3
  import { Injector } from '../../injector/injector.js';
4
4
  import { isDefined } from '../../utils/type-guards.js';
5
5
  import { AuthenticationClientService } from './authentication.service.js';
6
- import { authenticationMiddleware, waitForAuthenticationCredentialsMiddleware } from './http-client.middleware.js';
6
+ import { authenticationMiddleware, logoutOnUnauthorizedMiddleware, waitForAuthenticationCredentialsMiddleware } from './http-client.middleware.js';
7
7
  import { AUTHENTICATION_API_CLIENT, INITIAL_AUTHENTICATION_DATA } from './tokens.js';
8
8
  /**
9
9
  * Configures authentication client services.
@@ -24,6 +24,12 @@ export function configureAuthenticationClient(config, injector = getCurrentInjec
24
24
  return waitForAuthenticationCredentialsMiddleware(authenticationService);
25
25
  },
26
26
  }, { multi: true });
27
+ (injector ?? Injector).register(HTTP_CLIENT_MIDDLEWARE, {
28
+ useFactory(_, context) {
29
+ const authenticationService = context.resolve(AuthenticationClientService, undefined, { forwardRef: true, forwardRefTypeHint: 'object' });
30
+ return logoutOnUnauthorizedMiddleware(authenticationService);
31
+ },
32
+ }, { multi: true });
27
33
  (injector ?? Injector).register(HTTP_CLIENT_MIDDLEWARE, {
28
34
  useFactory(_, context) {
29
35
  const authenticationService = context.resolve(AuthenticationClientService, undefined, { forwardRef: true, forwardRefTypeHint: 'object' });
@@ -44,7 +44,7 @@ export declare class AuthenticationApiController<AdditionalTokenPayload extends
44
44
  /**
45
45
  * End a session.
46
46
  * @param request The request context.
47
- * @returns 'ok' if the session was ended.
47
+ * @returns 'ok'
48
48
  */
49
49
  endSession({ request, getAuditor }: ApiRequestContext<AuthenticationApiDefinition<AdditionalTokenPayload, AuthenticationData, AdditionalInitSecretResetData>, 'endSession'>): Promise<ApiServerResult<AuthenticationApiDefinition<AdditionalTokenPayload, AuthenticationData, AdditionalInitSecretResetData>, 'endSession'>>;
50
50
  changeSecret({ parameters, getAuditor }: ApiRequestContext<AuthenticationApiDefinition<AdditionalTokenPayload, AuthenticationData, AdditionalInitSecretResetData>, 'changeSecret'>): Promise<ApiServerResult<AuthenticationApiDefinition<AdditionalTokenPayload, AuthenticationData, AdditionalInitSecretResetData>, 'changeSecret'>>;
@@ -69,7 +69,7 @@ let AuthenticationApiController = class AuthenticationApiController {
69
69
  /**
70
70
  * End a session.
71
71
  * @param request The request context.
72
- * @returns 'ok' if the session was ended.
72
+ * @returns 'ok'
73
73
  */
74
74
  async endSession({ request, getAuditor }) {
75
75
  let sessionId;
@@ -85,10 +85,12 @@ let AuthenticationApiController = class AuthenticationApiController {
85
85
  sessionId = refreshToken.payload.session;
86
86
  }
87
87
  catch {
88
- throw error;
88
+ // ignore
89
89
  }
90
90
  }
91
- await this.authenticationService.endSession(sessionId, await getAuditor());
91
+ if (isDefined(sessionId)) {
92
+ await this.authenticationService.endSession(sessionId, await getAuditor());
93
+ }
92
94
  const result = 'ok';
93
95
  return new HttpServerResponse({
94
96
  cookies: {
@@ -22,12 +22,15 @@ export function tryGetAuthorizationTokenStringFromRequest(request, cookieName =
22
22
  const authorizationString = (isArray(headerValue) ? headerValue[0] : headerValue)
23
23
  ?? request.cookies.tryGet(cookieName);
24
24
  if (isDefined(authorizationString)) {
25
- const authorizationSchemeEnd = authorizationString.indexOf(' ');
26
- const authorizationScheme = authorizationString.slice(0, authorizationSchemeEnd).trim().toLowerCase();
25
+ const spaceIndex = authorizationString.indexOf(' ');
26
+ if (spaceIndex == -1) {
27
+ return authorizationString;
28
+ }
29
+ const authorizationScheme = authorizationString.slice(0, spaceIndex).trim().toLowerCase();
27
30
  if (authorizationScheme != 'bearer') {
28
31
  throw new BadRequestError(`Unsupported authorization scheme "${authorizationScheme}".`);
29
32
  }
30
- const authorization = authorizationString.slice(authorizationSchemeEnd).trim();
33
+ const authorization = authorizationString.slice(spaceIndex).trim();
31
34
  return authorization;
32
35
  }
33
36
  return undefined;
@@ -17,6 +17,17 @@ describe('authentication helper', () => {
17
17
  };
18
18
  expect(tryGetAuthorizationTokenStringFromRequest(request)).toBe('my-token');
19
19
  });
20
+ test('tryGetAuthorizationTokenStringFromRequest should extract token without scheme from header', () => {
21
+ const request = {
22
+ headers: {
23
+ tryGet: (name) => name == 'Authorization' ? 'my-token' : undefined,
24
+ },
25
+ cookies: {
26
+ tryGet: () => undefined,
27
+ },
28
+ };
29
+ expect(tryGetAuthorizationTokenStringFromRequest(request)).toBe('my-token');
30
+ });
20
31
  test('tryGetAuthorizationTokenStringFromRequest should extract bearer token from cookie', () => {
21
32
  const request = {
22
33
  headers: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tstdl/base",
3
- "version": "0.93.112",
3
+ "version": "0.93.114",
4
4
  "author": "Patrick Hein",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -152,7 +152,7 @@
152
152
  },
153
153
  "peerDependencies": {
154
154
  "@genkit-ai/google-genai": "^1.28",
155
- "@google-cloud/storage": "^7.18",
155
+ "@google-cloud/storage": "^7.19",
156
156
  "@google/genai": "^1.40",
157
157
  "@toon-format/toon": "^2.1.0",
158
158
  "@tstdl/angular": "^0.93",