Skip to Content
Canadian SIN

Validating a Canadian SIN: what the number knows, and what it doesn’t

A Canadian Social Insurance Number is nine digits with a Luhn check digit. Validating that takes ten lines of code, and most SIN validators stop there.

That is the easy part, and it answers almost nothing. 000 000 000 passes the Luhn check. So does a business number. So does a temporary resident’s SIN that expired last month. The interesting questions about a SIN are the ones the check digit cannot answer — and one of them comes before any validation at all.


First: should you be asking?

In the private sector, you generally may not require a SIN. Employers need it to report income, and financial institutions need it to report interest and dividends. Outside those purposes, the federal government’s guidance to individuals is that a business asking for a SIN is “strongly discouraged, but not illegal” — and that “you cannot be denied a product or service for refusing to provide your SIN when it is not legally required.”

The Office of the Privacy Commissioner goes further: the SIN “should not be used as a general identifier”, and organisations should restrict its collection, use and disclosure to legislated purposes.

So if your signup form has a SIN field because it seemed like a good way to identify people, the best validation is deleting the field. Everything below assumes you have a legal reason to hold one — typically payroll or HR onboarding, or a financial account that earns income.


What the number can tell you

It is well formed

Nine digits, and a Luhn check digit that catches a mistyped digit or two swapped neighbours. That is all a checksum does.

It belongs to a temporary resident

SINs issued to temporary residents always start with 9, and — this is the part that matters — they expire, on the same date as the holder’s work permit, study permit or visitor record.

The number does not carry that date. A 9-series SIN that validates perfectly today may belong to someone whose permit ended last month. Service Canada’s code of practice puts the onus on the employer: verify the terms of the work permit before hiring, and when documents expire, the employee updates their SIN record with the new expiry date.

It is not a personal SIN at all

Numbers starting with 0 are used for tax numbers the Canada Revenue Agency assigns to people who cannot get a SIN; numbers starting with 8 for business numbers. Both pass a Luhn check.

Service Canada does not publish its allocation, so treat this as well-established rather than official — which is why VerifNow reports it rather than rejecting on it.

{ "valid": true, "message": "Valid SIN format, but numbers starting with 0 are not issued to individuals", "normalizedValue": "046454286", "nasDetails": { "checksum_valid": true, "temporary_resident": false, "individual_series": false, "formatted": "046 454 286" } }

What the number cannot tell you

  • The expiry date of a temporary resident’s SIN. It is on the immigration document.
  • The province. The first digit once meant the province of registration, but numbers have been issued across series when a region ran short. Any API that returns a province from the first digit is guessing, and VerifNow does not.
  • Whether it was ever issued, and to whom. Only Service Canada holds that. Validation catches typos and impossible numbers; it does not prove identity, and a SIN is not an identity document — the government says so explicitly.

The decision, for payroll onboarding

ResultDo
valid: falseReject, and show message — it says whether the length or the check digit is wrong.
individual_series: falseReject. It is not a SIN issued to a person: often a business number, or a CRA tax number entered where the SIN was asked.
temporary_resident: trueAccept, and require the permit expiry date. Store it, and schedule a reminder before it passes.
OtherwiseAccept.
import { VerifNow } from '@verifnow/sdk'; const client = new VerifNow({ apiKey: process.env.VERIFNOW_API_KEY! }); type EmployeeInput = { sin: string; permitExpiry?: string }; export async function checkEmployeeSin({ sin, permitExpiry }: EmployeeInput) { const result = await client.validateNas(sin); const details = result.nasDetails; if (!result.valid || !details) { return { ok: false as const, error: result.message ?? 'That SIN is not valid.' }; } if (!details.individualSeries) { return { ok: false as const, error: 'That number is not a SIN issued to a person. Please check your SIN confirmation letter.', }; } if (details.temporaryResident && !permitExpiry) { // A 9-series SIN expires with the holder's permit, and the number does not say when. return { ok: false as const, error: 'Please enter the expiry date shown on your work permit.', }; } return { ok: true as const, sin: result.normalizedValue!, last3: result.normalizedValue!.slice(-3), expiresOn: details.temporaryResident ? permitExpiry : undefined, }; }

Needs @verifnow/sdk 1.4.0 or later, which models nasDetails. For Java, io.verifnow:verifnow-spring 2.4.0 or later exposes the same fields through getNasDetails().

The snippet returns the last three digits separately for a reason: that is what your screens should show. Nobody in your support team needs to read a full SIN.


Storing it

A SIN is the most sensitive number most Canadians have. If you hold one:

  • encrypt it at rest, and keep it out of the columns your analytics and BI tools read;
  • display it masked — the last three digits are enough to recognise it;
  • never log it — not in request logs, error trackers or validation audit trails;
  • never use it as a customer or employee identifier, which is exactly what the Privacy Commissioner advises against;
  • keep it only as long as the legal reason lasts.

On our side, the usage log that meters your calls stores a SIN as ***, with no digits at all.


Testing without anyone’s SIN

Use 046 454 286, the sample number the government prints on example cards. It starts with 0, so it cannot be anyone’s — and VerifNow will tell you so, with individual_series: false, which makes it a good test of your rejection path too.

Do not invent a “valid” number for the happy path. About one nine-digit number in ten has a correct check digit, and tens of millions of SINs have been issued: a made-up valid number stands a real chance of being a real person’s. If a test needs one, compute its check digit at run time from a prefix, and do not commit the result.


In short

  • Ask for a SIN only where the law requires it. Otherwise, remove the field.
  • Reject numbers that fail the check digit, and numbers not issued to individuals.
  • Accept a temporary resident’s SIN, but capture the permit expiry — the number cannot give it to you.
  • Encrypt, mask, never log, and never use it as an identifier.

Next: Validate SIN (NAS) · Validating a B2B signup form

Sources: Protect your Social Insurance Number  (Government of Canada) · SIN for temporary residents  (Government of Canada) · The SIN Code of Practice  (Government of Canada) · Best practices for the use of SINs in the private sector  (Office of the Privacy Commissioner of Canada)

Last updated on