-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
Secure connexion between TinyBird and webhookResponseGraph #7913
Conversation
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.
PR Summary
This pull request introduces JWT support for secure connections between TinyBird and the webhook response graph. Key changes include:
- Added
analyticsTinybirdJwt
field to User type in GraphQL schema - Created new
useAnalyticsTinybirdJwt
hook for retrieving TinyBird JWT - Modified
fetchGraphDataOrThrow
to use JWT for TinyBird API authorization - Updated AnalyticsService to generate and use JWT for TinyBird authentication
- Added new environment variables for TinyBird JWT configuration
- Integrated AnalyticsModule into UserModule and UserResolver
These changes enhance security by replacing hardcoded tokens with dynamic JWTs for TinyBird data access.
11 file(s) reviewed, 18 comment(s)
Edit PR Review Bot Settings | Greptile
@@ -7,6 +7,7 @@ export type CurrentUser = Pick< | |||
| 'id' | |||
| 'email' | |||
| 'supportUserHash' | |||
| 'analyticsTinybirdJwt' |
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.
style: Consider adding a comment explaining the purpose of 'analyticsTinybirdJwt' for future maintainers
@@ -0,0 +1,8 @@ | |||
import { useRecoilValue } from 'recoil'; |
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.
style: consider using more specific imports from recoil to reduce bundle size
|
||
export const useAnalyticsTinybirdJwt = (): string | null | undefined => { | ||
const currentUser = useRecoilValue(currentUserState); | ||
return currentUser?.analyticsTinybirdJwt; |
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.
style: consider adding a null check before accessing analyticsTinybirdJwt
import { fetchGraphDataOrThrow } from '@/settings/developers/webhook/utils/fetchGraphDataOrThrow'; | ||
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar'; | ||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; | ||
|
||
export const useGraphData = (webhookId: string) => { | ||
const { enqueueSnackBar } = useSnackBar(); | ||
const supportTinybirdJwt = useAnalyticsTinybirdJwt(); |
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.
style: Consider adding a comment explaining the purpose of supportTinybirdJwt
const fetchGraphData = async ( | ||
windowLengthGraphOption: '7D' | '1D' | '12H' | '4H', | ||
) => { | ||
try { | ||
return await fetchGraphDataOrThrow({ | ||
webhookId, | ||
windowLength: windowLengthGraphOption, | ||
tinybirdJwt: supportTinybirdJwt ?? undefined, |
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.
style: Use optional chaining instead of nullish coalescing
], | ||
}; | ||
|
||
return this.jwtService.sign(payload); |
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.
logic: JWT signing options (like expiration) are not specified. Consider adding these for better security.
|
||
@IsString() | ||
@ValidateIf((env) => env.ANALYTICS_ENABLED) | ||
TINYBIRD_TOKEN_EXPIRES_IN: 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.
style: Consider adding a validator to ensure TINYBIRD_TOKEN_EXPIRES_IN is a valid duration string
@@ -55,6 +56,7 @@ export class UserResolver { | |||
private readonly onboardingService: OnboardingService, | |||
private readonly userVarService: UserVarsService, | |||
private readonly fileService: FileService, | |||
private readonly analyticsservice: AnalyticsService, |
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.
syntax: Typo in service name: 'analyticsservice' should be 'analyticsService'
async analyticsTinybirdJwt( | ||
@AuthWorkspace() workspace: Workspace | undefined, | ||
): Promise<string | null> { | ||
return await this.analyticsservice.generateJWT(workspace?.id); | ||
} |
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.
logic: Consider adding error handling for cases where JWT generation fails
@ResolveField(() => String, { | ||
nullable: true, | ||
}) | ||
async analyticsTinybirdJwt( | ||
@AuthWorkspace() workspace: Workspace | undefined, | ||
): Promise<string | null> { | ||
return await this.analyticsservice.generateJWT(workspace?.id); | ||
} |
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.
style: Add documentation for the new analyticsTinybirdJwt field
|
||
import { currentUserState } from '@/auth/states/currentUserState'; | ||
|
||
export const useAnalyticsTinybirdJwt = (): string | null | undefined => { |
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.
can it be null
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.
yes it can be null when ANALYTICS is not enabled in the server
const fetchGraphData = async ( | ||
windowLengthGraphOption: '7D' | '1D' | '12H' | '4H', | ||
) => { | ||
try { | ||
return await fetchGraphDataOrThrow({ | ||
webhookId, | ||
windowLength: windowLengthGraphOption, | ||
tinybirdJwt: supportTinybirdJwt ?? undefined, |
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.
?? undefined is not useful, we should throw before if the jwt is undefined
@@ -4,22 +4,24 @@ import { WEBHOOK_GRAPH_API_OPTIONS_MAP } from '@/settings/developers/webhook/con | |||
type fetchGraphDataOrThrowProps = { | |||
webhookId: string; | |||
windowLength: '7D' | '1D' | '12H' | '4H'; | |||
tinybirdJwt?: 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.
should be required
@@ -1,17 +1,34 @@ | |||
/* eslint-disable no-restricted-imports */ |
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.
why?
@@ -58,7 +60,7 @@ export class AnalyticsService { | |||
const config: AxiosRequestConfig = { | |||
headers: { | |||
Authorization: | |||
'Bearer ' + this.environmentService.get('TINYBIRD_TOKEN'), | |||
'Bearer ' + this.environmentService.get('TINYBIRD_DATASOURCE_TOKEN'), |
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.
TINYBIRD_INGEST_TOKEN
(vs TINYBIRD_GENERATE_JWT_TOKEN)
@@ -86,4 +88,22 @@ export class AnalyticsService { | |||
|
|||
return { success: true }; | |||
} | |||
|
|||
async generateJWT(workspaceId: string | null | undefined) { |
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.
generateWorkspaceJwt
@@ -55,6 +56,7 @@ export class UserResolver { | |||
private readonly onboardingService: OnboardingService, | |||
private readonly userVarService: UserVarsService, | |||
private readonly fileService: FileService, | |||
private readonly analyticsservice: AnalyticsService, |
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.
analyticsService
|
||
@IsString() | ||
@ValidateIf((env) => env.ANALYTICS_ENABLED) | ||
TINYBIRD_TOKEN: string; | ||
TINYBIRD_DATASOURCE_TOKEN: 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.
add these to doc
TLDR:
Secure connexion between tinybird and twenty using jwt when accessing datasource from tinybird.
Solves:
https://github.com/twentyhq/private-issues/issues/73
In order to test: