Skip to content

Commit 680b4d8

Browse files
feat: clean up auth flow (#290)
Make the cookie with refresh token strict and request bound - exact host Refactor oidc discovery service to recive an url as a parameter --------- Co-authored-by: Grzegorz Krajniak <[email protected]>
1 parent fc072b0 commit 680b4d8

File tree

7 files changed

+26
-33
lines changed

7 files changed

+26
-33
lines changed

src/auth/auth-config.service.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,8 @@ export class EnvAuthConfigService implements AuthConfigService {
110110

111111
const idpEnvName = this.formatIdpNameForEnvVar(idpName);
112112

113-
const oidc = await this.discoveryService.getOIDC(idpEnvName);
113+
const oidcUrl = process.env[`DISCOVERY_ENDPOINT_${idpEnvName}`];
114+
const oidc = await this.discoveryService.getOIDC(oidcUrl);
114115
const oauthServerUrl =
115116
oidc?.authorization_endpoint ??
116117
process.env[`AUTH_SERVER_URL_${idpEnvName}`];

src/auth/auth-token.service.spec.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,10 @@ describe('AuthTokenService', () => {
7777
'openmfp_auth_cookie',
7878
refreshTokenValue,
7979
{
80-
domain: 'example.com',
8180
path: '/',
8281
httpOnly: true,
8382
secure: true,
84-
sameSite: 'lax',
83+
sameSite: 'strict',
8584
},
8685
);
8786
}

src/auth/auth-token.service.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { EnvService } from '../env/env.service.js';
1+
import { EnvService } from '../env/index.js';
22
import { AUTH_CONFIG_INJECTION_TOKEN } from '../injection-tokens.js';
33
import { CookiesService } from '../services/index.js';
44
import {
@@ -43,7 +43,7 @@ export class AuthTokenService {
4343
code: string,
4444
): Promise<AuthTokenData> {
4545
const authConfig = await this.authConfigService.getAuthConfig(request);
46-
const redirectUri = this.getRedirectUri(request, authConfig);
46+
const redirectUri = this.getRedirectUri(request);
4747

4848
const body = new URLSearchParams({
4949
client_id: authConfig.clientId,
@@ -127,10 +127,7 @@ export class AuthTokenService {
127127
* When running locally after executing token retrieval the call will be redirected to localhost and port set in FRONTEND_PORT system variable,
128128
* otherwise to the host of the initiating request
129129
*/
130-
private getRedirectUri(
131-
request: Request,
132-
currentAuthEnv: ServerAuthVariables,
133-
) {
130+
private getRedirectUri(request: Request) {
134131
let redirectionUrl: string;
135132
const env = this.envService.getEnv();
136133
const isStandardOrEmptyPort =
@@ -141,7 +138,7 @@ export class AuthTokenService {
141138
if (env.isLocal) {
142139
redirectionUrl = `http://localhost${port}`;
143140
} else {
144-
redirectionUrl = `https://${currentAuthEnv.baseDomain}${port}`;
141+
redirectionUrl = `https://${request.hostname}${port}`;
145142
}
146143
return `${redirectionUrl}/callback?storageType=none`;
147144
}

src/env/discovery.service.spec.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { DiscoveryService } from './discovery.service';
1+
import { DiscoveryService } from './discovery.service.js';
22
import { HttpService } from '@nestjs/axios';
33
import { Test, TestingModule } from '@nestjs/testing';
44
import { AxiosError } from 'axios';
@@ -52,11 +52,11 @@ describe('DiscoveryService', () => {
5252
'example.com/authorization_endpoint',
5353
);
5454
expect(oidc.token_endpoint).toEqual('example.com/token_endpoint');
55-
expect(service['oidcResultPerIdp']['APP']).toEqual({
55+
expect(service['oidcResultPerUrl']['APP']).toEqual({
5656
authorization_endpoint: 'example.com/authorization_endpoint',
5757
token_endpoint: 'example.com/token_endpoint',
5858
});
59-
expect(service['oidcResultPerIdp']['APP2']).toBeUndefined();
59+
expect(service['oidcResultPerUrl']['APP2']).toBeUndefined();
6060
});
6161

6262
it('should not get oauthServerUrl and oauthTokenUrl and throw error when httpService returns error', async () => {
@@ -89,13 +89,13 @@ describe('DiscoveryService', () => {
8989

9090
process.env['DISCOVERY_ENDPOINT_APP'] = 'example.com';
9191

92-
await expect(service.getOIDC('APP')).rejects.toThrow(
92+
await expect(service.getOIDC('example.com')).rejects.toThrow(
9393
'Invalid response from discovery service: Response status: 101, OIDC endpoint: example.com',
9494
);
9595
});
9696

9797
it('should get null when DISCOVERY_ENDPOINT does not exist', async () => {
98-
const oidc = await service.getOIDC('APP');
98+
const oidc = await service.getOIDC('');
9999

100100
expect(oidc).toBeNull();
101101
});
@@ -116,7 +116,7 @@ describe('DiscoveryService', () => {
116116

117117
process.env['DISCOVERY_ENDPOINT_APP'] = 'example.com';
118118

119-
await expect(service.getOIDC('APP')).rejects.toThrow(
119+
await expect(service.getOIDC('example.com')).rejects.toThrow(
120120
'Invalid response from discovery service: Response status: 200, OIDC endpoint: example.com',
121121
);
122122
});
@@ -138,10 +138,10 @@ describe('DiscoveryService', () => {
138138

139139
process.env['DISCOVERY_ENDPOINT_APP'] = 'example.com';
140140

141-
await expect(service.getOIDC('APP')).rejects.toThrow(
141+
await expect(service.getOIDC('example.com')).rejects.toThrow(
142142
'Invalid response from discovery service: Response status: 200, OIDC endpoint: example.com',
143143
);
144-
expect(service['oidcResultPerIdp']['APP']).toBeUndefined();
144+
expect(service['oidcResultPerUrl']['example.com']).toBeUndefined();
145145
});
146146
});
147147
});

src/env/discovery.service.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,15 @@ interface OIDC {
1010

1111
@Injectable()
1212
export class DiscoveryService {
13-
private oidcResultPerIdp: Record<string, OIDC> = {};
13+
private oidcResultPerUrl: Record<string, OIDC> = {};
1414

1515
constructor(private httpService: HttpService) {}
1616

17-
public async getOIDC(idpEnvName: string): Promise<OIDC> {
18-
const oidcUrl = process.env[`DISCOVERY_ENDPOINT_${idpEnvName}`];
17+
public async getOIDC(oidcUrl: string): Promise<OIDC> {
1918
if (!oidcUrl) return null;
2019

21-
if (this.oidcResultPerIdp[idpEnvName]) {
22-
return this.oidcResultPerIdp[idpEnvName];
20+
if (this.oidcResultPerUrl[oidcUrl]) {
21+
return this.oidcResultPerUrl[oidcUrl];
2322
}
2423

2524
const oidcResult = await firstValueFrom(
@@ -36,7 +35,7 @@ export class DiscoveryService {
3635
const oidc = oidcResult.data;
3736

3837
if (oidc.authorization_endpoint && oidc.token_endpoint) {
39-
this.oidcResultPerIdp[idpEnvName] = oidc;
38+
this.oidcResultPerUrl[oidcUrl] = oidc;
4039
return oidc;
4140
}
4241
}

src/services/cookies.service.spec.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { AuthTokenData } from '../auth/auth-token.service.js';
1+
import { AuthTokenData } from '../auth/index.js';
22
import { CookiesService } from './cookies.service.js';
33
import { Test, TestingModule } from '@nestjs/testing';
44
import type { Request, Response } from 'express';
@@ -56,11 +56,10 @@ describe('CookiesService', () => {
5656
'openmfp_auth_cookie',
5757
'test-refresh-token',
5858
{
59-
domain: 'test-hostname',
6059
path: '/',
6160
httpOnly: true,
6261
secure: true,
63-
sameSite: 'lax',
62+
sameSite: 'strict',
6463
},
6564
);
6665
});
@@ -81,10 +80,9 @@ describe('CookiesService', () => {
8180
expect(mockResponse.clearCookie).toHaveBeenCalledWith(
8281
'openmfp_auth_cookie',
8382
{
84-
domain: 'test-hostname',
8583
httpOnly: true,
8684
path: '/',
87-
sameSite: 'lax',
85+
sameSite: 'strict',
8886
secure: true,
8987
},
9088
);

src/services/cookies.service.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { AuthTokenData } from '../auth/auth-token.service.js';
1+
import { AuthTokenData } from '../auth/index.js';
22
import { Injectable } from '@nestjs/common';
33
import type { Request, Response } from 'express';
44

@@ -27,13 +27,12 @@ export class CookiesService {
2727
response.clearCookie(authCookie, this.cookieParams(request));
2828
}
2929

30-
private cookieParams(request: Request) {
30+
private cookieParams(_request: Request) {
3131
return {
32-
domain: request.hostname,
3332
httpOnly: true,
3433
secure: true,
3534
path: '/',
36-
sameSite: 'lax',
35+
sameSite: 'strict',
3736
};
3837
}
3938
}

0 commit comments

Comments
 (0)