Generated page. Written from IdaMilk/paycor-microsoft-integration at commit ed40c36 on 2026-07-28, version 1.0.0.
Paycor → Microsoft 365 Onboarding
What is it?
An Azure Functions app that watches Paycor for new hires and provisions their Microsoft 365 / Entra ID account: creates and enables the user, maps their employee data, assigns a licence and security groups based on job title, and hands a temporary password to IT.
When someone's job title changes in Paycor, it reconciles their groups and licence to match.
Purpose
Onboarding is repetitive and easy to get subtly wrong — a missed group means someone cannot do their job on day one; a missed removal on a role change means lingering access nobody notices.
Driving both from Paycor, which HR already maintains, makes the HR record the source of truth rather than a ticket someone has to remember to file.
How it Works
Two triggers into one orchestrator: a timer (hourly by default) and an HTTP "run now" with a dry-run preview.
Timer (hourly) ─┐
├─► runSync orchestrator
HTTP "run now" ─┘
1. Acquire Paycor token per legal entity (rotating refresh token, persisted)
2. Fetch onboarding employees (paged)
3. Per employee, check persisted state:
new hire → create user → set usageLocation → assign licence → groups
job title changed → reconcile groups, swap licence, patch jobTitle/department
Several design choices are worth noting because they are the ones that make an integration like this survivable:
- Idempotent with persisted state. Re-running does not duplicate accounts. For a job that creates identities, this is the difference between a safe retry and a mess.
- Per-employee failure isolation. One bad record does not abort the run.
- Retry with backoff on 429 and 5xx, honouring
Retry-After. Both Graph and Paycor throttle. - Rotating refresh-token persistence. Paycor's refresh tokens rotate on use, so the new one must be stored or the next run cannot authenticate.
- Username collision handling —
jsmith→jsmith2→jsmith3. - Manually-added groups are never touched. Reconciliation only adds and removes groups the rules table drives, so an ad-hoc grant survives.
- Temporary passwords are generated strong, forced to change at first sign-in, and delivered only through the IT report channel — never written to logs or email.
Group and licence assignment is driven by an editable rules table keyed on job title (rules.sample.json), so onboarding policy changes are configuration, not code.
Mapped fields
Name, job title, department, office, employee ID, hire date, phone numbers, address, and usageLocation — the last being required before a licence can be assigned, which is why it is set as its own step.
Tech Stack
| Technology | Version | Purpose |
|---|---|---|
| Azure Functions | ^4.7.0 | Runtime (v4 programming model) |
| TypeScript | — | Language |
| @azure/identity | ^4.10.0 | Azure authentication |
| @azure/keyvault-secrets | ^4.10.0 | Secret storage |
| @azure/data-tables | ^13.3.1 | Persisted sync state |
| Microsoft Graph | — | Called directly, no SDK wrapper |
| Vitest | — | Testing |
Secrets live in Azure Key Vault rather than application settings — the right choice for credentials that can create identities.
Interfaces
| System | Direction | Purpose |
|---|---|---|
| Paycor API | inbound | Onboarding employee records, per legal entity |
| Microsoft Graph | outbound | User creation, licensing, group membership |
| Azure Key Vault | outbound | Credential retrieval |
| Azure Table Storage | both | Sync state and rotating refresh tokens |
Status
v1 complete but not production-validated. The README is explicit: 133 unit tests pass and the build is clean, but it has not been run against a live Paycor tenant. docs/KNOWN-LIMITATIONS.md and ROADMAP.md are required reading before deploying.
That combination — thorough tests, honest status — is worth more than a confident README would be. Treat the first live run as a supervised event, and use the HTTP dry-run preview before the timer is enabled.
Repository
| Repository | IdaMilk/paycor-microsoft-integration |
| Version | 1.0.0 |
| Primary language | TypeScript |
| Files | 54 |
| Last activity | 2026-06-26 |
| Status | v1 complete, awaiting production validation |
The only Azure-hosted project in the organisation, and the only one with a substantial unit test suite. docs/superpowers/ retains the design spec and implementation plan.