Use additionalScopes for Okta auth instead of overriding scope entirely

Signed-off-by: ataylorme <andrew@ataylor.me>
This commit is contained in:
ataylorme
2023-10-26 05:29:03 -07:00
parent 1185e30cb4
commit 8466307819
5 changed files with 29 additions and 21 deletions
+1
View File
@@ -131,6 +131,7 @@ export interface Config {
authServerId?: string;
idp?: string;
callbackUrl?: string;
additionalScopes?: string;
};
};
/** @visibility frontend */
@@ -105,6 +105,7 @@ describe('createOktaProvider', () => {
});
it('should pass a custom scope to start and refresh requests', async () => {
const additionalScopes = 'groups';
const mockScope = 'openid profile email offline_access groups';
const reqScope = 'openid profile email offline_access';
const provider = new OktaAuthProvider({
@@ -119,7 +120,7 @@ describe('createOktaProvider', () => {
clientId: 'mock',
clientSecret: 'mock',
callbackUrl: 'mock',
scope: mockScope,
additionalScopes,
});
mockRedirectStrategy.mockResolvedValueOnce({
@@ -60,7 +60,7 @@ export type OktaAuthProviderOptions = OAuthProviderOptions & {
signInResolver?: SignInResolver<OAuthResult>;
authHandler: AuthHandler<OAuthResult>;
resolverContext: AuthResolverContext;
scope?: string;
additionalScopes?: string;
};
export class OktaAuthProvider implements OAuthHandlers {
@@ -68,7 +68,7 @@ export class OktaAuthProvider implements OAuthHandlers {
private readonly signInResolver?: SignInResolver<OAuthResult>;
private readonly authHandler: AuthHandler<OAuthResult>;
private readonly resolverContext: AuthResolverContext;
private readonly scope: string;
private readonly additionalScopes: string;
/**
* Due to passport-okta-oauth forcing options.state = true,
@@ -91,7 +91,7 @@ export class OktaAuthProvider implements OAuthHandlers {
this.signInResolver = options.signInResolver;
this.authHandler = options.authHandler;
this.resolverContext = options.resolverContext;
this.scope = options.scope || 'openid email profile offline_access';
this.additionalScopes = options.additionalScopes || '';
this.strategy = new OktaStrategy(
{
@@ -128,11 +128,19 @@ export class OktaAuthProvider implements OAuthHandlers {
);
}
private combineScopeStrings(scopesA: string, scopesB: string) {
const scopesAArray = scopesA.split(' ');
const scopesBArray = scopesB.split(' ');
const combinedScopes = new Set([...scopesAArray, ...scopesBArray]);
return Array.from(combinedScopes).join(' ');
}
async start(req: OAuthStartRequest): Promise<OAuthStartResponse> {
const scope = this.combineScopeStrings(req.scope, this.additionalScopes);
return await executeRedirectStrategy(req, this.strategy, {
accessType: 'offline',
prompt: 'consent',
scope: this.scope,
scope: scope,
state: encodeState(req.state),
});
}
@@ -150,12 +158,9 @@ export class OktaAuthProvider implements OAuthHandlers {
}
async refresh(req: OAuthRefreshRequest) {
const scope = this.combineScopeStrings(req.scope, this.additionalScopes);
const { accessToken, refreshToken, params } =
await executeRefreshTokenStrategy(
this.strategy,
req.refreshToken,
this.scope,
);
await executeRefreshTokenStrategy(this.strategy, req.refreshToken, scope);
const fullProfile = await executeFetchUserProfileStrategy(
this.strategy,
@@ -233,7 +238,8 @@ export const okta = createAuthProviderIntegration({
const callbackUrl =
customCallbackUrl ||
`${globalConfig.baseUrl}/${providerId}/handler/frame`;
const scope = envConfig.getOptionalString('scope');
const additionalScopes =
envConfig.getOptionalString('additionalScopes');
// This is a safe assumption as `passport-okta-oauth` uses the audience
// as the base for building the authorization, token, and user info URLs.
@@ -258,7 +264,7 @@ export const okta = createAuthProviderIntegration({
authHandler,
signInResolver: options?.signIn?.resolver,
resolverContext,
scope,
additionalScopes,
});
return OAuthAdapter.fromConfig(globalConfig, provider, {