Skip to content

Commit 446a0cc

Browse files
committed
Challenge API integration final fixes
1 parent d5c2e17 commit 446a0cc

19 files changed

+403
-129
lines changed

.env

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,28 @@ SCHEMA_REGISTRY_PASSWORD=
4343
# -------------------------------------
4444
# The base URL for the Topcoder Challenge API v6
4545
CHALLENGE_API_URL=https://api.topcoder-dev.com/v6
46-
# A valid M2M token for authenticating with the Challenge API
47-
CHALLENGE_API_M2M_TOKEN='your_m2m_token_here'
46+
# Removed static M2M token - now using Auth0 service
4847
# The number of retry attempts for failed Challenge API calls
4948
CHALLENGE_API_RETRY_ATTEMPTS=3
5049
# The initial delay (in ms) for the first retry attempt
5150
CHALLENGE_API_RETRY_DELAY=1000
5251

52+
# -------------------------------------
53+
# Auth0 Configuration
54+
# -------------------------------------
55+
# The Auth0 URL for token generation (full OAuth endpoint)
56+
AUTH0_URL=<your-auth0-url>
57+
# Client ID for M2M application
58+
AUTH0_CLIENT_ID=<your-auth0-client-id>
59+
# Client secret for M2M application
60+
AUTH0_CLIENT_SECRET=<your-auth0-client-secret>
61+
# The Auth0 domain
62+
AUTH0_DOMAIN=<your-auth0-domain>
63+
# The audience/API identifier for the Challenge API
64+
AUTH0_AUDIENCE=<your-auth0-audience>
65+
# Auth0 proxy server URL (optional)
66+
AUTH0_PROXY_SEREVR_URL=
67+
5368
# -------------------------------------
5469
# Sync Service Configuration
5570
# -------------------------------------

.env.example

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,28 @@ SCHEMA_REGISTRY_PASSWORD=
4343
# -------------------------------------
4444
# The base URL for the Topcoder Challenge API v6
4545
CHALLENGE_API_URL=https://api.topcoder-dev.com/v6
46-
# A valid M2M token for authenticating with the Challenge API
47-
CHALLENGE_API_M2M_TOKEN='your_m2m_token_here'
46+
# Removed static M2M token - now using Auth0 service
4847
# The number of retry attempts for failed Challenge API calls
4948
CHALLENGE_API_RETRY_ATTEMPTS=3
5049
# The initial delay (in ms) for the first retry attempt
5150
CHALLENGE_API_RETRY_DELAY=1000
5251

52+
# -------------------------------------
53+
# Auth0 Configuration
54+
# -------------------------------------
55+
# The Auth0 URL for token generation (full OAuth endpoint)
56+
AUTH0_URL=<your-auth0-url>
57+
# Client ID for M2M application
58+
AUTH0_CLIENT_ID=<your-auth0-client-id>
59+
# Client secret for M2M application
60+
AUTH0_CLIENT_SECRET=<your-auth0-client-secret>
61+
# The Auth0 domain
62+
AUTH0_DOMAIN=<your-auth0-domain>
63+
# The audience/API identifier for the Challenge API
64+
AUTH0_AUDIENCE=<your-auth0-audience>
65+
# Auth0 proxy server URL (optional)
66+
AUTH0_PROXY_SEREVR_URL=
67+
5368
# -------------------------------------
5469
# Sync Service Configuration
5570
# -------------------------------------

README.md

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ Create a `.env` file in the root directory:
3131
cp .env.example .env
3232
```
3333

34-
Open the `.env` file and configure the variables for your environment. It is crucial to set a valid `CHALLENGE_API_M2M_TOKEN`.
34+
Open the `.env` file and configure the variables for your environment. It is crucial to set valid Auth0 credentials.
3535

3636
```plaintext
3737
# -------------------------------------
@@ -57,10 +57,19 @@ Open the `.env` file and configure the variables for your environment. It is cru
5757
# Challenge API Configuration
5858
# -------------------------------------
5959
CHALLENGE_API_URL=https://api.topcoder-dev.com/v6
60-
CHALLENGE_API_M2M_TOKEN='your_m2m_token_here' # <-- IMPORTANT: REPLACE THIS
6160
CHALLENGE_API_RETRY_ATTEMPTS=3
6261
CHALLENGE_API_RETRY_DELAY=1000
6362
63+
# -------------------------------------
64+
# Auth0 Configuration
65+
# -------------------------------------
66+
AUTH0_URL=<your-auth0-url> # <-- IMPORTANT: REPLACE THIS
67+
AUTH0_CLIENT_ID=<your-auth0-client-id> # <-- IMPORTANT: REPLACE THIS
68+
AUTH0_CLIENT_SECRET=<your-auth0-client-secret> # <-- IMPORTANT: REPLACE THIS
69+
AUTH0_DOMAIN=<your-auth0-domain> # <-- IMPORTANT: REPLACE THIS
70+
AUTH0_AUDIENCE=<your-auth0-audience> # <-- IMPORTANT: REPLACE THIS
71+
AUTH0_PROXY_SEREVR_URL=
72+
6473
# -------------------------------------
6574
# Sync Service Configuration
6675
# -------------------------------------
@@ -218,4 +227,4 @@ For more detailed technical information, please see the documents in the `docs/`
218227
docker compose up -d
219228
```
220229

221-
- **API Authentication Errors**: Ensure `CHALLENGE_API_M2M_TOKEN` in your `.env` file is valid and not expired.
230+
- **API Authentication Errors**: Ensure Auth0 credentials (`AUTH0_URL`, `AUTH0_CLIENT_ID`, `AUTH0_CLIENT_SECRET`, `AUTH0_AUDIENCE`) in your `.env` file are valid and not expired.

docker-compose.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
version: '3.8'
2-
31
services:
42
zookeeper:
53
image: confluentinc/cp-zookeeper:7.4.0

src/auth/auth0.module.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { Module } from '@nestjs/common';
2+
import { HttpModule } from '@nestjs/axios';
3+
import { Auth0Service } from './auth0.service';
4+
5+
@Module({
6+
imports: [HttpModule],
7+
providers: [Auth0Service],
8+
exports: [Auth0Service],
9+
})
10+
export class Auth0Module {}

src/auth/auth0.service.ts

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import { Injectable, Logger } from '@nestjs/common';
2+
import { ConfigService } from '@nestjs/config';
3+
import { HttpService } from '@nestjs/axios';
4+
import { firstValueFrom } from 'rxjs';
5+
6+
interface Auth0TokenResponse {
7+
access_token: string;
8+
token_type: string;
9+
expires_in: number;
10+
}
11+
12+
interface Auth0TokenCache {
13+
token: string;
14+
expiresAt: number;
15+
}
16+
17+
@Injectable()
18+
export class Auth0Service {
19+
private readonly logger = new Logger(Auth0Service.name);
20+
private readonly auth0Url: string;
21+
private readonly clientId: string;
22+
private readonly clientSecret: string;
23+
private readonly audience: string;
24+
private tokenCache: Auth0TokenCache | null = null;
25+
26+
constructor(
27+
private readonly httpService: HttpService,
28+
private readonly configService: ConfigService,
29+
) {
30+
this.auth0Url = this.configService.get<string>('auth0.url') || '';
31+
this.clientId = this.configService.get<string>('auth0.clientId') || '';
32+
this.clientSecret =
33+
this.configService.get<string>('auth0.clientSecret') || '';
34+
this.audience = this.configService.get<string>('auth0.audience') || '';
35+
36+
if (
37+
!this.auth0Url ||
38+
!this.clientId ||
39+
!this.clientSecret ||
40+
!this.audience
41+
) {
42+
this.logger.error(
43+
'Missing required Auth0 configuration. Please check AUTH0_URL, AUTH0_CLIENT_ID, AUTH0_CLIENT_SECRET, and AUTH0_AUDIENCE environment variables.',
44+
);
45+
}
46+
}
47+
48+
async getAccessToken(): Promise<string> {
49+
// Check if we have a valid cached token
50+
if (this.tokenCache && Date.now() < this.tokenCache.expiresAt) {
51+
this.logger.debug('Using cached Auth0 token');
52+
return this.tokenCache.token;
53+
}
54+
55+
try {
56+
this.logger.log('Requesting new Auth0 M2M token');
57+
58+
const tokenUrl = this.auth0Url; // Use the full URL from config
59+
const body = {
60+
client_id: this.clientId,
61+
client_secret: this.clientSecret,
62+
audience: this.audience,
63+
grant_type: 'client_credentials',
64+
};
65+
66+
const response = await firstValueFrom(
67+
this.httpService.post<Auth0TokenResponse>(tokenUrl, body, {
68+
headers: {
69+
'Content-Type': 'application/json',
70+
},
71+
timeout: 10000,
72+
}),
73+
);
74+
75+
const { access_token, expires_in } = response.data;
76+
77+
// Cache the token with a buffer (subtract 60 seconds to ensure we refresh before expiry)
78+
const expiresAt = Date.now() + (expires_in - 60) * 1000;
79+
this.tokenCache = {
80+
token: access_token,
81+
expiresAt,
82+
};
83+
84+
this.logger.log('Successfully obtained new Auth0 M2M token');
85+
return access_token;
86+
} catch (error) {
87+
const err = error as Error;
88+
this.logger.error(
89+
`Failed to obtain Auth0 M2M token: ${err.message}`,
90+
err.stack,
91+
);
92+
throw new Error('Failed to obtain Auth0 access token');
93+
}
94+
}
95+
96+
clearTokenCache(): void {
97+
this.logger.log('Clearing Auth0 token cache');
98+
this.tokenCache = null;
99+
}
100+
}

src/autopilot/interfaces/autopilot.interface.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export interface CommandPayload {
3333
command: string;
3434
operator: string;
3535
projectId?: number;
36+
challengeId?: string; // Added challengeId for new command handling
3637
date?: string;
3738
phaseId?: string; // Changed from number to string
3839
}

0 commit comments

Comments
 (0)