public setupRoutes()

in server/auth/types/openid/routes.ts [58:212]


  public setupRoutes() {
    this.router.get(
      {
        path: `/auth/openid/login`,
        validate: {
          query: schema.object(
            {
              code: schema.maybe(schema.string()),
              nextUrl: schema.maybe(
                schema.string({
                  validate: validateNextUrl,
                })
              ),
              state: schema.maybe(schema.string()),
              refresh: schema.maybe(schema.string()),
            },
            {
              unknowns: 'allow',
            }
          ),
        },
        options: {
          authRequired: false,
        },
      },
      async (context, request, response) => {
        // implementation refers to https://github.com/hapijs/bell/blob/master/lib/oauth.js

        // Sign-in initialization
        if (!request.query.code) {
          const nonce = randomString(OpenIdAuthRoutes.NONCE_LENGTH);
          const query: any = {
            client_id: this.config.openid?.client_id,
            response_type: 'code',
            redirect_uri: `${getBaseRedirectUrl(this.config, this.core)}/auth/openid/login`,
            state: nonce,
            scope: this.openIdAuthConfig.scope,
          };

          const queryString = stringify(query);
          const location = `${this.openIdAuthConfig.authorizationEndpoint}?${queryString}`;
          const cookie: SecuritySessionCookie = {
            oidc: {
              state: nonce,
              nextUrl: request.query.nextUrl || '/',
            },
          };
          this.sessionStorageFactory.asScoped(request).set(cookie);
          return response.redirected({
            headers: {
              location,
            },
          });
        }

        // Authentication callback

        // validate state first
        let cookie;
        try {
          cookie = await this.sessionStorageFactory.asScoped(request).get();
          if (
            !cookie ||
            !cookie.oidc?.state ||
            cookie.oidc.state !== (request.query as any).state
          ) {
            return this.redirectToLogin(request, response);
          }
        } catch (error) {
          return this.redirectToLogin(request, response);
        }
        const nextUrl: string = cookie.oidc.nextUrl;

        const clientId = this.config.openid?.client_id;
        const clientSecret = this.config.openid?.client_secret;
        const query: any = {
          grant_type: 'authorization_code',
          code: request.query.code,
          redirect_uri: `${getBaseRedirectUrl(this.config, this.core)}/auth/openid/login`,
          client_id: clientId,
          client_secret: clientSecret,
        };

        try {
          const tokenResponse = await callTokenEndpoint(
            this.openIdAuthConfig.tokenEndpoint!,
            query,
            this.wreckClient
          );

          const user = await this.securityClient.authenticateWithHeader(
            request,
            this.openIdAuthConfig.authHeaderName as string,
            `Bearer ${tokenResponse.idToken}`
          );

          // set to cookie
          const sessionStorage: SecuritySessionCookie = {
            username: user.username,
            credentials: {
              authHeaderValue: `Bearer ${tokenResponse.idToken}`,
              expires_at: Date.now() + tokenResponse.expiresIn! * 1000, // expiresIn is in second
            },
            authType: 'openid',
            expiryTime: Date.now() + this.config.session.ttl,
          };
          if (this.config.openid?.refresh_tokens && tokenResponse.refreshToken) {
            Object.assign(sessionStorage.credentials, {
              refresh_token: tokenResponse.refreshToken,
            });
          }
          this.sessionStorageFactory.asScoped(request).set(sessionStorage);
          return response.redirected({
            headers: {
              location: nextUrl,
            },
          });
        } catch (error) {
          context.security_plugin.logger.error(`OpenId authentication failed: ${error}`);
          // redirect to login
          return this.redirectToLogin(request, response);
        }
      }
    );

    this.router.get(
      {
        path: `/auth/logout`,
        validate: false,
      },
      async (context, request, response) => {
        const cookie = await this.sessionStorageFactory.asScoped(request).get();
        this.sessionStorageFactory.asScoped(request).clear();

        // authHeaderValue is the bearer header, e.g. "Bearer <auth_token>"
        const token = cookie?.credentials.authHeaderValue.split(' ')[1]; // get auth token
        const logoutQueryParams = {
          post_logout_redirect_uri: getBaseRedirectUrl(this.config, this.core),
          id_token_hint: token,
        };

        const endSessionUrl = composeLogoutUrl(
          this.config.openid?.logout_url,
          this.openIdAuthConfig.endSessionEndpoint,
          logoutQueryParams
        );

        return response.redirected({
          headers: {
            location: endSessionUrl,
          },
        });
      }
    );
  }