-
Notifications
You must be signed in to change notification settings - Fork 0
PM-1437 Feat/auth #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
PM-1437 - Use canActivate for tools
export const decodeAuthToken = async ( | ||
authHeader: string, | ||
): Promise<boolean | jwt.JwtPayload | string> => { | ||
const [type, idToken] = authHeader?.split(' ') ?? []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
high
correctness
The use of optional chaining (authHeader?.split(' ')
) may lead to a runtime error if authHeader
is undefined
. Consider adding a check for authHeader
before attempting to split it.
let decoded: jwt.JwtPayload | string; | ||
try { | ||
const signingKey = await getSigningKey(idToken); | ||
decoded = jwt.verify(idToken, signingKey); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
medium
maintainability
The jwt.verify
function can throw an error if the token is expired or invalid. While the error is caught, consider handling specific error types to provide more informative logging or responses.
const signingKey = await getSigningKey(idToken); | ||
decoded = jwt.verify(idToken, signingKey); | ||
} catch (error) { | ||
logger.error('Error verifying JWT', error); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
high
security
Logging the error object directly may expose sensitive information. Consider sanitizing the error message before logging.
export const checkM2MScope = | ||
(...requiredM2mScopes: M2mScope[]) => | ||
async (req: Request) => { | ||
const decodedAuth = await decodeAuthToken(req.headers.authorization ?? ''); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
medium
correctness
The use of req.headers.authorization ?? ''
assumes that an empty string is a valid input for decodeAuthToken
. Consider handling cases where the authorization header is missing more explicitly, potentially returning an error or a specific response.
async (req: Request) => { | ||
const decodedAuth = await decodeAuthToken(req.headers.authorization ?? ''); | ||
|
||
const authorizedScopes = ((decodedAuth as JwtPayload).scope ?? '').split( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
medium
correctness
The scope
claim is split by spaces, which assumes that scopes are space-separated. Ensure this assumption aligns with the JWT format used in your application, as different formats might use different separators.
export const checkHasUserRole = | ||
(...requiredUserRoles: Role[]) => | ||
async (req: Request) => { | ||
const decodedAuth = await decodeAuthToken(req.headers.authorization ?? ''); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
high
correctness
Consider handling the case where decodeAuthToken
returns null
or an unexpected structure to avoid runtime errors. This could be done by adding a check after decoding the token.
const decodedAuth = await decodeAuthToken(req.headers.authorization ?? ''); | ||
|
||
const decodedUserRoles = Object.keys(decodedAuth).reduce((roles, key) => { | ||
if (key.match(/claims\/roles$/gi)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
medium
correctness
The use of Object.keys(decodedAuth)
and reduce
may lead to unexpected behavior if decodedAuth
is not an object or if the keys do not match the expected pattern. Consider validating the structure of decodedAuth
before processing.
return roles; | ||
}, []); | ||
|
||
if (!requiredUserRoles.some((role) => decodedUserRoles.includes(role))) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
medium
performance
The use of some
with includes
could be optimized for performance by using a set for decodedUserRoles
if the list is large, as includes
has O(n) complexity.
import { Injectable, Inject } from '@nestjs/common'; | ||
import { Tool } from '@rekog/mcp-nest'; | ||
import { Tool } from '@tc/mcp-nest'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
high
correctness
The import path for Tool
has changed from @rekog/mcp-nest
to @tc/mcp-nest
. Ensure that this change is intentional and that the new module provides the same functionality as the previous one.
import { REQUEST } from '@nestjs/core'; | ||
import { QUERY_CHALLENGES_TOOL_PARAMETERS } from './queryChallenges.parameters'; | ||
import { TopcoderChallengesService } from 'src/shared/topcoder/challenges.service'; | ||
import { Logger } from 'src/shared/global'; | ||
import { QUERY_CHALLENGES_TOOL_OUTPUT_SCHEMA } from './queryChallenges.output'; | ||
import { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
high
security
Consider verifying that the newly imported authentication guards (authGuard
, checkHasUserRole
, checkM2MScope
) are correctly integrated and used within the tool. This is crucial for ensuring the security layer is properly enforced.
}, | ||
}) | ||
async queryChallenges(params) { | ||
private async _queryChallenges(params) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
medium
design
Renaming queryChallenges
to _queryChallenges
suggests it is intended to be private. Ensure that this change aligns with the intended design and usage within the application, as it may affect how this method is accessed or overridden.
|
||
@Tool({ | ||
name: 'query-tc-challenges-private', | ||
description: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
medium
correctness
The description for query-tc-challenges-private
mentions public challenges, which seems inconsistent with the tool name suggesting private challenges. Ensure the description accurately reflects the functionality.
|
||
@Tool({ | ||
name: 'query-tc-challenges-protected', | ||
description: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
medium
correctness
The description for query-tc-challenges-protected
mentions public challenges, which may not align with the intended functionality for protected challenges. Verify that the description matches the tool's purpose.
} | ||
|
||
@Tool({ | ||
name: 'query-tc-challenges-m2m', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
medium
correctness
The description for query-tc-challenges-m2m
mentions public challenges, which might not be accurate for machine-to-machine scope. Confirm that the description is appropriate for the intended use case.
} | ||
|
||
@Tool({ | ||
name: 'query-tc-challenges-public', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
medium
security
Consider adding an authentication guard to query-tc-challenges-public
to ensure consistent security practices across all query methods.
@@ -24,10 +19,7 @@ export class Logger extends NestLogger { | |||
} | |||
|
|||
private formatMessages(messages: any[]): string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
medium
maintainability
The removal of the requestIdPrefix
could impact the ability to trace logs back to specific requests. If this was intentional, consider documenting how request tracing will be handled elsewhere.
Adds auth layer to the MCP server: https://topcoder.atlassian.net/browse/PM-1437