Skip to content

Commit

Permalink
♻️ api: make certification result token configurable
Browse files Browse the repository at this point in the history
  • Loading branch information
Steph0 committed Dec 4, 2024
1 parent 771a05b commit 91e2445
Show file tree
Hide file tree
Showing 6 changed files with 29 additions and 19 deletions.
14 changes: 14 additions & 0 deletions api/sample.env
Original file line number Diff line number Diff line change
Expand Up @@ -783,6 +783,20 @@ TEST_REDIS_URL=redis://localhost:6379
# default: false
# FT_ENABLE_CERTIF_TOKEN_SCOPE=false

# Control the scope of certification result tokens
#
# presence: optional
# type: string
# default: certificationResultsLink
# CERTIFICATION_RESULTS_JWT_SCOPE=certificationResultsLink

# Control the lifespan of certification result tokens
#
# presence: optional
# type: string
# default: 30d
# CERTIFICATION_RESULTS_JWT_TOKEN_LIFE_SPAN=30d

# Enable the text to speech button on challenges
#
# presence: optional
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
import { config } from '../../../../shared/config.js';
import { tokenService } from '../../../../shared/domain/services/token-service.js';

const generateResultsLink = function ({ sessionId, i18n }) {
const daysBeforeExpiration = 30;

const token = tokenService.createCertificationResultsLinkToken({ sessionId, daysBeforeExpiration });
export const generateResultsLink = function ({ sessionId, i18n }) {
const token = tokenService.createCertificationResultsLinkToken({ sessionId });
const lang = i18n.getLocale();
const link = `${config.domain.pixApp + config.domain.tldOrg}/resultats-session#${token}?lang=${lang}`;

return link;
return `${config.domain.pixApp + config.domain.tldOrg}/resultats-session#${token}?lang=${lang}`;
};

export { generateResultsLink };
4 changes: 4 additions & 0 deletions api/src/shared/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,10 @@ const configuration = (function () {
secret: process.env.PIX_DATA_AUTH_SECRET,
tokenLifespan: process.env.TOKEN_LIFE_SPAN || '1h',
},
certificationResults: {
scope: process.env.CERTIFICATION_RESULTS_JWT_SCOPE || 'certificationResultsLink',
tokenLifespan: process.env.CERTIFICATION_RESULTS_JWT_TOKEN_LIFE_SPAN || '30d',
},
},
lcms: {
url: _removeTrailingSlashFromUrl(process.env.CYPRESS_LCMS_API_URL || process.env.LCMS_API_URL || ''),
Expand Down
9 changes: 4 additions & 5 deletions api/src/shared/domain/services/token-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
InvalidTemporaryKeyError,
} from '../errors.js';

const CERTIFICATION_RESULTS_LINK_SCOPE = 'certificationResultsLink';
const CERTIFICATION_RESULTS_BY_RECIPIENT_EMAIL_LINK_SCOPE = 'certificationResultsByRecipientEmailLink';

function _createAccessToken({ userId, source, expirationDelaySeconds }) {
Expand Down Expand Up @@ -93,15 +92,15 @@ function createCertificationResultsByRecipientEmailLinkToken({
);
}

function createCertificationResultsLinkToken({ sessionId, daysBeforeExpiration }) {
function createCertificationResultsLinkToken({ sessionId }) {
return jsonwebtoken.sign(
{
session_id: sessionId,
scope: CERTIFICATION_RESULTS_LINK_SCOPE,
scope: config.jwtConfig.certificationResults.scope,
},
config.authentication.secret,
{
expiresIn: `${daysBeforeExpiration}d`,
expiresIn: `${config.jwtConfig.certificationResults.tokenLifespan}`,
},
);
}
Expand Down Expand Up @@ -172,7 +171,7 @@ function extractCertificationResultsLink(token) {
}

if (config.featureToggles.isCertificationTokenScopeEnabled) {
if (decoded.scope !== CERTIFICATION_RESULTS_LINK_SCOPE) {
if (decoded.scope !== config.jwtConfig.certificationResults.scope) {
throw new InvalidSessionResultTokenError();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ describe('Certification | Results | Unit | Domain | Service | Session Results Li
const sessionId = 12345;
const i18n = getI18n();
const tokenServiceStub = sinon.stub(tokenService, 'createCertificationResultsLinkToken');
tokenServiceStub.withArgs({ sessionId, daysBeforeExpiration: 30 }).returns('a_valid_token');
tokenServiceStub.withArgs({ sessionId }).returns('a_valid_token');

// when
const link = sessionResultsLinkService.generateResultsLink({ sessionId, i18n });
Expand Down
7 changes: 3 additions & 4 deletions api/tests/shared/unit/domain/services/token-service_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import lodash from 'lodash';
const { omit } = lodash;
import jsonwebtoken from 'jsonwebtoken';

import { config as settings } from '../../../../../src/shared/config.js';
import { config, config as settings } from '../../../../../src/shared/config.js';
import {
ForbiddenAccess,
InvalidExternalUserTokenError,
Expand Down Expand Up @@ -229,7 +229,7 @@ describe('Unit | Shared | Domain | Services | Token Service', function () {
scope: 'certificationResultsLink',
},
settings.authentication.secret,
{ expiresIn: '30d' },
{ expiresIn: config.jwtConfig.certificationResults.tokenLifespan },
);

// when
Expand Down Expand Up @@ -463,14 +463,13 @@ describe('Unit | Shared | Domain | Services | Token Service', function () {
it('should return a valid token with sessionId and resultRecipientEmail', function () {
// given
const sessionId = 'abcd1234';
const daysBeforeExpiration = 30;
const expectedTokenAttributes = {
session_id: 'abcd1234',
scope: 'certificationResultsLink',
};

// when
const linkToken = tokenService.createCertificationResultsLinkToken({ sessionId, daysBeforeExpiration });
const linkToken = tokenService.createCertificationResultsLinkToken({ sessionId });

// then
const decodedToken = jsonwebtoken.verify(linkToken, settings.authentication.secret);
Expand Down

0 comments on commit 91e2445

Please sign in to comment.