auth-backend-module-github-provider: reject refresh for sessions without granted scope

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2025-02-12 12:18:22 +01:00
parent ab9a6fb321
commit b40af03894
3 changed files with 34 additions and 4 deletions
@@ -42,7 +42,7 @@ describe('githubAuthenticator', () => {
accessToken: 'my-token',
scope: 'user:read',
tokenType: 'bearer',
refreshToken: 'access-token.my-token',
refreshToken: 'access-token-v2.my-token',
},
});
});
@@ -105,9 +105,10 @@ describe('githubAuthenticator', () => {
await expect(
githubAuthenticator.refresh(
{
refreshToken: 'access-token.my-token',
refreshToken: 'access-token-v2.my-token',
req: {} as any,
scope: 'user:read',
scopeAlreadyGranted: true,
},
{
fetchProfile: async _input => ({ id: 'id' } as PassportProfile),
@@ -119,11 +120,28 @@ describe('githubAuthenticator', () => {
accessToken: 'my-token',
scope: 'user:read',
tokenType: 'bearer',
refreshToken: 'access-token.my-token',
refreshToken: 'access-token-v2.my-token',
},
});
});
it('should fail refresh if scope has not already been granted', async () => {
await expect(
githubAuthenticator.refresh(
{
refreshToken: 'access-token-v2.my-token',
req: {} as any,
scope: 'user:read',
},
{
fetchProfile: async _input => ({ id: 'id' } as PassportProfile),
} as PassportOAuthAuthenticatorHelper,
),
).rejects.toThrow(
'Refresh failed, session has not been granted the requested scope',
);
});
it('should refresh with refresh token', async () => {
const res = {};
await expect(
@@ -22,7 +22,7 @@ import {
PassportProfile,
} from '@backstage/plugin-auth-node';
const ACCESS_TOKEN_PREFIX = 'access-token.';
const ACCESS_TOKEN_PREFIX = 'access-token-v2.';
/** @public */
export const githubAuthenticator = createOAuthAuthenticator({
@@ -98,6 +98,11 @@ export const githubAuthenticator = createOAuthAuthenticator({
// refresh token cookie. We use that token to fetch the user profile and
// refresh the Backstage session when needed.
if (input.refreshToken?.startsWith(ACCESS_TOKEN_PREFIX)) {
if (!input.scopeAlreadyGranted) {
throw new Error(
'Refresh failed, session has not been granted the requested scope',
);
}
const accessToken = input.refreshToken.slice(ACCESS_TOKEN_PREFIX.length);
const fullProfile = await helper