diff --git a/api/sample.env b/api/sample.env index a53cf2aaa45..82fe4f95e19 100644 --- a/api/sample.env +++ b/api/sample.env @@ -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 diff --git a/api/src/certification/results/domain/services/session-results-link-service.js b/api/src/certification/results/domain/services/session-results-link-service.js index 748b3b7959b..924542432c1 100644 --- a/api/src/certification/results/domain/services/session-results-link-service.js +++ b/api/src/certification/results/domain/services/session-results-link-service.js @@ -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 }; diff --git a/api/src/shared/config.js b/api/src/shared/config.js index de749df236e..6b727255bcd 100644 --- a/api/src/shared/config.js +++ b/api/src/shared/config.js @@ -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 || ''), diff --git a/api/src/shared/domain/services/token-service.js b/api/src/shared/domain/services/token-service.js index acc9f5d9f22..2ec0a6f8c0c 100644 --- a/api/src/shared/domain/services/token-service.js +++ b/api/src/shared/domain/services/token-service.js @@ -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 }) { @@ -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}`, }, ); } @@ -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(); } } diff --git a/api/tests/certification/results/unit/domain/services/session-results-link-service_test.js b/api/tests/certification/results/unit/domain/services/session-results-link-service_test.js index fd4d4632f34..b3f1af1916a 100644 --- a/api/tests/certification/results/unit/domain/services/session-results-link-service_test.js +++ b/api/tests/certification/results/unit/domain/services/session-results-link-service_test.js @@ -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 }); diff --git a/api/tests/shared/unit/domain/services/token-service_test.js b/api/tests/shared/unit/domain/services/token-service_test.js index b083dc4b409..10c84efc910 100644 --- a/api/tests/shared/unit/domain/services/token-service_test.js +++ b/api/tests/shared/unit/domain/services/token-service_test.js @@ -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, @@ -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 @@ -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);