_private/qwestly-hire-docs/plan/unify-external-api-auth.md
Table of Contents
Unify external job search auth with companies
Current gap
| Area | Today |
|---|---|
[src/app/api/external/search/companies/[[...slug]]/route.ts](src/app/api/external/search/companies/[[...slug]]/route.ts) |
Uses [createExternalApiRouter()](src/lib/external-api-auth.ts) โ **HIRE_APP_API_KEY** |
[src/app/api/external/search/jobs/[[...slug]]/route.ts](src/app/api/external/search/jobs/[[...slug]]/route.ts) |
Done: uses createExternalApiRouter() โ HIRE_APP_API_KEY |
[src/proxy.ts](src/proxy.ts) already lists **/api/external** as public (session bypass for API-key-only callers). CORS already allows **X-API-Key**. Route groups (external) were not used; real **/api/external/...** URLs are in placeโno change needed there.
Implementation (hire repo)
- Refactor jobs external router โ In
[src/app/api/external/search/jobs/[[...slug]]/route.ts](src/app/api/external/search/jobs/[[...slug]]/route.ts):
- Remove direct
ApiRouter+isAuthenticatedViaApiKey(..., JOB_SEARCH_API_KEY)construction. - Import
**createExternalApiRouter** from[src/lib/external-api-auth.ts](src/lib/external-api-auth.ts)and use the same pattern as companies (single lineconst router = createExternalApiRouter();). - Keep all existing
router.gethandlers andhandleError/ serialization logic unchanged.
- Documentation
- Update
[docs/external-jobs-search-api.md](docs/external-jobs-search-api.md): state authentication uses**HIRE_APP_API_KEY** (same as other/api/external/*routes); replace examples sayingJOB_SEARCH_API_KEY/ โJob Search API keyโ with**HIRE_APP_API_KEY**and note one key for all external integration endpoints on Hire. - Optionally add a short cross-link in
[docs/features/company-search-external.md](docs/features/company-search-external.md)(or a single โExternal APIsโ bullet) that job search under/api/external/search/jobsshares the same key and router helper as company search.
- Env template
- Extend the comment above
**HIRE_APP_API_KEY** in[.env.copy](.env.copy)to explicitly include**GET /api/external/search/jobs**(and any sub-routes documented). Do not addJOB_SEARCH_API_KEYas a separate required variable.
- Tests
- If any test or script references
JOB_SEARCH_API_KEY, update toHIRE_APP_API_KEYor remove (grep shows none outside jobs route + docs today).
Deploy / consumer migration
- Vercel / env: Remove
**JOB_SEARCH_API_KEY** from Hire project settings (or stop setting it). Ensure**HIRE_APP_API_KEY**is set to the value integrations should use. - Any client that was configured with a distinct job-search secret must send
**HIRE_APP_API_KEY** instead when calling**/api/external/search/jobs**. Today candidate[hire-app.service.ts]still uses**/api/admin/jobs** withHIRE_APP_API_KEYโno candidate change until product switches job listing to the external jobs API. Document this in the PR description.
Out of scope (unless you expand the ticket)
- Optional hardening from the separate review (max
qlength, Zod on Rapid envelope, body size limits, rate limiting); track as follow-up PRs.