Skip to content

Commit 6d2de22

Browse files
committed
Talent manager permissions for BAs (https://topcoder.atlassian.net/browse/PM-4376)
1 parent 57b5cca commit 6d2de22

17 files changed

Lines changed: 222 additions & 88 deletions

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@
2323
**Authorization**
2424
- JWT middleware via `tc-core-library-js` attaches `req.authUser`
2525
- Guards for Roles (e.g., `Administrator`) and M2M Scopes are provided.
26+
- Billing-account management endpoints accept `administrator`, `Talent Manager`,
27+
and `Topcoder Talent Manager` JWT roles; read-only billing-account lookups
28+
also continue to allow `copilot`. Role checks are case-insensitive so mixed
29+
token casing does not block Talent Manager access.
2630
- Configure env: `AUTH_SECRET` or `AUTH0_URL/AUDIENCE/ISSUER` as needed.
2731

2832
## Quickstart

src/auth/auth.middleware.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
import { Injectable, NestMiddleware } from "@nestjs/common";
22
import { Request, Response, NextFunction } from "express";
3-
4-
// tc-core-library-js is CommonJS only, import via require
5-
6-
const tcCore = require("tc-core-library-js");
3+
import * as tcCore from "tc-core-library-js";
74

85
@Injectable()
96
export class AuthMiddleware implements NestMiddleware {

src/auth/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,5 @@ export const SCOPES = {
1313

1414
export const ADMIN_ROLE = "administrator";
1515
export const COPILOT_ROLE = "copilot";
16+
export const TALENT_MANAGER_ROLE = "Talent Manager";
17+
export const TOPCODER_TALENT_MANAGER_ROLE = "Topcoder Talent Manager";

src/auth/guards/roles.guard.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ export class RolesGuard implements CanActivate {
1919
context.getClass(),
2020
]);
2121
if (!required || required.length === 0) return true;
22+
const normalizedRequiredRoles = required.map((role) =>
23+
role.trim().toLowerCase(),
24+
);
2225

2326
const req = context.switchToHttp().getRequest();
2427
const user = req.authUser;
@@ -31,24 +34,33 @@ export class RolesGuard implements CanActivate {
3134
.split(",")
3235
.map((r: string) => r.trim())
3336
.filter(Boolean);
37+
const normalizedRoles = roles.map((role) => role.toLowerCase());
3438

35-
const ok = roles.some((r: string) => required.includes(r));
39+
const ok = normalizedRoles.some((role: string) =>
40+
normalizedRequiredRoles.includes(role),
41+
);
3642
if (ok) return true;
3743

3844
const fallbackScopes = this.reflector.getAllAndOverride<string[]>(
3945
SCOPES_KEY,
40-
[context.getHandler(), context.getClass()]
46+
[context.getHandler(), context.getClass()],
4147
);
4248

4349
if (fallbackScopes && fallbackScopes.length > 0) {
50+
const normalizedFallbackScopes = fallbackScopes.map((scope) =>
51+
scope.trim().toLowerCase(),
52+
);
4453
const scopes: string[] = Array.isArray(user.scopes)
4554
? user.scopes
4655
: (user.scope || "")
4756
.split(" ")
4857
.map((s: string) => s.trim())
4958
.filter(Boolean);
59+
const normalizedScopes = scopes.map((scope) => scope.toLowerCase());
5060

51-
const scopeOk = fallbackScopes.some((s) => scopes.includes(s));
61+
const scopeOk = normalizedScopes.some((scope) =>
62+
normalizedFallbackScopes.includes(scope),
63+
);
5264
if (scopeOk) return true;
5365
}
5466

src/auth/guards/scopes.guard.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@ export class ScopesGuard implements CanActivate {
3535
const ok = required.some((s) => scopes.includes(s));
3636
if (ok) return true;
3737

38-
const fallbackRoles = this.reflector.getAllAndOverride<string[]>(ROLES_KEY, [
39-
context.getHandler(),
40-
context.getClass(),
41-
]);
38+
const fallbackRoles = this.reflector.getAllAndOverride<string[]>(
39+
ROLES_KEY,
40+
[context.getHandler(), context.getClass()],
41+
);
4242

4343
if (fallbackRoles && fallbackRoles.length > 0) {
4444
const roles: string[] = Array.isArray(user.roles)

0 commit comments

Comments
 (0)