Skip to content

Commit 0465020

Browse files
committedApr 4, 2025
feat(mon-pix): prevent OIDC authentication replay errors when doing history back and reload
i.e. 400 BadRequestError 'Required "state" is missing in session' This is when the user is already authenticated with the same OIDC Provider and performs a reload of the /connexion/:identity_provider_slug URL.
1 parent 6de23bc commit 0465020

File tree

2 files changed

+43
-1
lines changed

2 files changed

+43
-1
lines changed
 

Diff for: ‎mon-pix/app/routes/authentication/login-oidc.js

+11-1
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,20 @@ export default class LoginOidcRoute extends Route {
2828
throw error;
2929
}
3030

31+
const identityProviderSlug = transition.to.params.identity_provider_slug.toString();
32+
33+
// Preventing OIDC authentication replay errors when doing history back and reload
34+
// when the user is already authenticated with the same OIDC Provider.
35+
if (this.session.isAuthenticated) {
36+
const identityProvider = this.oidcIdentityProviders[identityProviderSlug];
37+
if (identityProvider.code == this.session.data.identityProviderCode) {
38+
return this.router.replaceWith('authenticated');
39+
}
40+
}
41+
3142
if (!queryParams.code) {
3243
this._cleanSession();
3344

34-
const identityProviderSlug = transition.to.params.identity_provider_slug.toString();
3545
if (this.oidcIdentityProviders.isProviderEnabled(identityProviderSlug)) {
3646
return this._handleRedirectRequest(identityProviderSlug);
3747
}

Diff for: ‎mon-pix/tests/unit/routes/authentication/login-oidc-test.js

+32
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { ApplicationError } from 'mon-pix/errors/application-error';
66
import { module, test } from 'qunit';
77
import sinon from 'sinon';
88

9+
import { stubSessionService } from '../../../helpers/service-stubs';
910
import setupIntl from '../../../helpers/setup-intl';
1011

1112
module('Unit | Route | login-oidc', function (hooks) {
@@ -36,6 +37,37 @@ module('Unit | Route | login-oidc', function (hooks) {
3637
});
3738
});
3839

40+
module('when the user is already authenticated', function () {
41+
test('redirects the user to the authenticated route', async function (assert) {
42+
// given
43+
const someOidcPartner = {
44+
id: 'some-oidc-provider',
45+
code: 'SOME_OIDC_PARTNER',
46+
};
47+
class OidcIdentityProvidersStub extends Service {
48+
'some-oidc-provider' = someOidcPartner;
49+
list = [someOidcPartner];
50+
isProviderEnabled = (identityProviderSlug) => {
51+
return Boolean(identityProviderSlug == 'some-oidc-provider');
52+
};
53+
}
54+
this.owner.register('service:oidcIdentityProviders', OidcIdentityProvidersStub);
55+
56+
const route = this.owner.lookup('route:authentication/login-oidc');
57+
const replaceWithStub = sinon.stub();
58+
route.router = {
59+
replaceWith: replaceWithStub,
60+
};
61+
stubSessionService(this.owner, { isAuthenticated: true, identityProviderCode: 'SOME_OIDC_PARTNER' });
62+
63+
// when
64+
await route.beforeModel({ to: { queryParams: {}, params: { identity_provider_slug: 'some-oidc-provider' } } });
65+
66+
// then
67+
assert.ok(replaceWithStub.calledWith('authenticated'));
68+
});
69+
});
70+
3971
module('when no code exists in queryParams', function (hooks) {
4072
hooks.beforeEach(function () {
4173
sinon.stub(fetch, 'default').resolves({

0 commit comments

Comments
 (0)