• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

alkem-io / server / #7853

02 Aug 2024 08:51AM UTC coverage: 13.641%. First build
#7853

Pull #4336

travis-ci

Pull Request #4336: Configuration service with typings

79 of 4106 branches covered (1.92%)

Branch coverage included in aggregate %.

31 of 78 new or added lines in 20 files covered. (39.74%)

1886 of 10299 relevant lines covered (18.31%)

2.91 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/core/middleware/session.extend.middleware.ts
1
import {
×
2
  Inject,
3
  Injectable,
4
  LoggerService,
5
  NestMiddleware,
6
} from '@nestjs/common';
7
import { ConfigService } from '@nestjs/config';
×
8
import { Request, Response, NextFunction } from 'express';
9
import { WINSTON_MODULE_NEST_PROVIDER } from 'nest-winston';
×
10
import { AuthenticationService } from '@core/authentication/authentication.service';
×
NEW
11
import { LogContext } from '@src/common/enums';
×
12
import { getSessionFromJwt } from '@common/utils';
×
13
import { Configuration, FrontendApi, Session } from '@ory/kratos-client';
×
14
import { AlkemioConfig } from '@src/types';
15

16
@Injectable()
17
export class SessionExtendMiddleware implements NestMiddleware {
×
18
  private readonly SESSION_COOKIE_NAME: string;
19
  private readonly enabled: boolean;
20
  private readonly kratosClient: FrontendApi;
21
  constructor(
22
    @Inject(WINSTON_MODULE_NEST_PROVIDER)
23
    private readonly logger: LoggerService,
×
24
    private readonly authService: AuthenticationService,
×
NEW
25
    private readonly configService: ConfigService<AlkemioConfig, true>
×
26
  ) {
NEW
27
    this.SESSION_COOKIE_NAME = this.configService.get(
×
28
      'identity.authentication.providers.ory.session_cookie_name',
NEW
29
      { infer: true }
×
30
    );
NEW
31

×
32
    this.enabled = this.configService.get(
33
      'identity.authentication.providers.ory.session_extend_enabled',
×
34
      { infer: true }
35
    );
36

37
    const kratosPublicBaseUrl = this.configService.get(
38
      'identity.authentication.providers.ory.kratos_public_base_url_server',
39
      { infer: true }
40
    );
41

×
42
    this.kratosClient = new FrontendApi(
×
43
      new Configuration({
44
        basePath: kratosPublicBaseUrl,
45
      })
×
46
    );
47
  }
×
48

×
49
  async use(req: Request, res: Response, next: NextFunction) {
50
    if (!this.enabled) {
51
      return next();
×
52
    }
53

54
    const authorization = req.headers['authorization'];
55

×
56
    if (!authorization) {
×
57
      this.logger.verbose?.(
58
        'Session extend middleware: authorization header not found'
×
59
      );
×
60
      return next();
61
    }
62

×
63
    let session: Session;
64
    try {
65
      session = getSessionFromJwt(authorization);
×
66
    } catch (e: any) {
×
67
      this.logger.verbose?.(
×
68
        `Error while extracting ory session: ${e?.message}`,
69
        LogContext.AUTH_TOKEN
×
70
      );
71
      return next();
72
    }
73

74
    if (this.authService.shouldExtendSession(session)) {
75
      try {
76
        await this.authService.extendSession(session);
×
77
      } catch (error) {
×
78
        this.logger.error(
×
79
          `Ory Kratos session failed to be extended: ${error}`,
80
          LogContext.AUTH
81
        );
82
      }
×
83

84
      const orySessionId: string | undefined =
85
        req.cookies[this.SESSION_COOKIE_NAME];
86
      if (!orySessionId) {
87
        this.logger.warn?.(
88
          'New session cookie not sent: new session id not found',
89
          LogContext.AUTH_TOKEN
90
        );
91
        return next();
92
      }
93

×
94
      /**
95
       * Session cookies in Ory Kratos are pass-by-value (meaning they are not just an id or a reference to a session).
96
       * When session is updated, new cookie must be obtained and sent to the client.
97
       * toSession() calls /sessions/whoami endpoint that handles that.
×
98
       * Another strategy (may be a more reliable one) is to call /sessions/whoami from the client for the cookies.
99
       * In that case we may want to set a special header (e.g. X-Session-Extended) to indicate that the session is extended,
×
100
       * that in turns will trigger the client to call /sessions/whoami.
101
       */
102
      const { headers } = await this.kratosClient.toSession({
×
103
        cookie: req.headers.cookie,
104
      });
105

106
      res.header('Set-Cookie', headers['set-cookie']);
107

108
      this.logger.verbose?.('New session cookie sent', LogContext.AUTH_TOKEN);
109
    }
110

111
    next();
112
  }
113
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc