Skip to content

DHIS2: Schema should not require username/password when using a PAT#1689

Merged
josephjclark merged 3 commits into
release/nextfrom
dhis2-schema-config
Jun 30, 2026
Merged

DHIS2: Schema should not require username/password when using a PAT#1689
josephjclark merged 3 commits into
release/nextfrom
dhis2-schema-config

Conversation

@PiusKariuki

@PiusKariuki PiusKariuki commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

Summary

The configuration schema requires username and password even when authenticating with a PAT, forcing users to provide credentials that are silently ignored.

The schema currently has:

"required": ["hostUrl", "password", "username"]

And configureAuth uses a priority chain — PAT wins over password:

if ('pat' in auth) {
  Object.assign(headers, { Authorization: `ApiToken ${auth.pat}` });
} else if ('password' in auth) {
  Object.assign(headers, makeBasicAuthHeader(auth.username, auth.password));
}

The password branch doesn't check that username is also present, so CLI users (where the schema isn't enforced) can end up with silent auth failures.

Fixes #1547

Details

The schema currently has:

"required": ["hostUrl", "password", "username"]

And configureAuth uses a priority chain — PAT wins over password:

if ('pat' in auth) {
  Object.assign(headers, { Authorization: `ApiToken ${auth.pat}` });
} else if ('password' in auth) {
  Object.assign(headers, makeBasicAuthHeader(auth.username, auth.password));
}

The password branch doesn't check that username is also present, so CLI users (where the schema isn't enforced) can end up with silent auth failures.

Expected behaviour

  1. Schema should express that credentials are one-of: either pat, or both username + password — not all three required. A oneOf/anyOf structure would work.
  2. Runtime: when falling back to Basic auth (no PAT), configureAuth should validate that both username and password are present and non-empty, and throw a descriptive error if either is missing.

AI Usage

Please disclose how you've used AI in this work (it's cool, we just want to
know!):

  • I have used Claude Code
  • I have used another model
  • I have not used AI

You can read more details in our
Responsible AI Policy

Review Checklist

Before merging, the reviewer should check the following items:

  • Does the PR do what it claims to do?
  • If this is a new adaptor, added the adaptor on marketing website ?
  • If this PR includes breaking changes, do we need to update any jobs in
    production? Is it safe to release?
  • Are there any unit tests?
  • Is there a changeset associated with this PR? Should there be? Note that
    dev only changes don't need a changeset.
  • Have you ticked a box under AI Usage?

Comment thread packages/dhis2/test/auth.test.js Outdated
expect(headers).to.eql(makeBasicAuthHeader('admin', 'district'));
});

it('should throw if pat is empty', () => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think on the unit test for configureAuth could be summarised into

it('should throw if no valid credentials are provided', () => {
  expect(() => util.configureAuth({})).to.throw('Invalid authorization...');
});

it('should throw if username is provided without a password', () => {
  expect(() => util.configureAuth({ username: 'admin', password: '' })).to.throw('Invalid authorization...');
});

I think the description should be very specific and tidy @PiusKariuki

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PiusKariuki where i am getting at is for example this description is not accurate
"should throw if pat is empty" because it will only throw if pat is empty and username and password is not provided

@josephjclark josephjclark Jun 12, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah these tests are a little peculiar.

They look thorough at first glance but:

  • in the test should throw if pat is empty, user name and password are all empty
  • you're testing "empty" but not null or undefined. Why is "empty" so significant?

They're not very tight, accurate, controlled tests. And they're actually quite misleading: should throw if pat is empty is simply not a reflection of the spec. I agree with Mtuchi's approach

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might also test for example that pat is preferred to username and password - that feels like an important thing to a) document in a test and b) preserve in a regression test

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • "should prioritize pat over username/password when both are present"
  • "should set Authorization header with ApiToken when pat is provided"
  • "should set Basic Auth header when username and password are provided (no pat)"

@mtuchi mtuchi left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PiusKariuki can you update the pr checklist notes and title, also since you updated the util we should have a changeset

@PiusKariuki PiusKariuki changed the title fix(auth): check credential values not just key presence, make userna… DHIS2: Schema should not require username/password when using a PAT Jun 12, 2026
@PiusKariuki

Copy link
Copy Markdown
Collaborator Author

@mtuchi You would like less tests? I think that would reduce our coverage in testing what was written in the spec. See link See below for things we would miss out on:

  1. Not testing the scenario where an empty string is passed in place of a PAT.
  2. Not testing the scenario where the configureAuth function would not check if a  ​username is present.

I have added a changeset file as requested and the PR checklist notes and title

@PiusKariuki PiusKariuki requested a review from mtuchi June 12, 2026 06:29
@PiusKariuki

Copy link
Copy Markdown
Collaborator Author

@josephjclark @mtuchi Got it. Thank you both for clarifying those issues on the tests. Key changes I have made:

  1. Dropped the misleading should throw if pat is empty test.
  2. Updated descriptions to accurately reflect what is being tested.
  3. Added the PAT priority test.

@PiusKariuki PiusKariuki requested a review from josephjclark June 25, 2026 05:18
@josephjclark josephjclark changed the base branch from main to release/next June 30, 2026 09:47
@josephjclark josephjclark merged commit 99b50c3 into release/next Jun 30, 2026
3 checks passed
@josephjclark josephjclark deleted the dhis2-schema-config branch June 30, 2026 09:48
josephjclark added a commit that referenced this pull request Jun 30, 2026
* bump sdk (#1708)

* DHIS2: Schema should not require username/password when using a PAT (#1689)

* fix(auth): check credential values not just key presence, make username/password optional in schema

* changeset file

* Revised the auth tests to be more descriptive

* build(deps): bump undici from 7.24.7 to 7.28.0 (#1694)

* build(deps): bump undici from 7.24.7 to 7.28.0

Bumps [undici](https://github.com/nodejs/undici) from 7.24.7 to 7.28.0.
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](nodejs/undici@v7.24.7...v7.28.0)

---
updated-dependencies:
- dependency-name: undici
  dependency-version: 7.28.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* changeset

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Joe Clark <joe@openfn.org>

* build(deps): bump esbuild from 0.27.4 to 0.28.1 (#1693)

Bumps [esbuild](https://github.com/evanw/esbuild) from 0.27.4 to 0.28.1.
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md)
- [Commits](evanw/esbuild@v0.27.4...v0.28.1)

---
updated-dependencies:
- dependency-name: esbuild
  dependency-version: 0.28.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* dhis2: Add paging examples and default `async:false` in `tracker.import` (#1681)

* feat: allow async value change

Signed-off-by: Hunter Achieng <achienghunter@gmail.com>

* feat: update tests

Signed-off-by: Hunter Achieng <achienghunter@gmail.com>

* feat: add changeset

Signed-off-by: Hunter Achieng <achienghunter@gmail.com>

* add integration tests for tracker.export

* add pagination example

* update example

* update integration test

* improve format

* remove async and add pagination docs

* update tracker unit tests

* update changeset

* fix typo

* fix: update chngeset and tracker pagination examples

Signed-off-by: Hunter Achieng <achienghunter@gmail.com>

* fix: update docs

Signed-off-by: Hunter Achieng <achienghunter@gmail.com>

---------

Signed-off-by: Hunter Achieng <achienghunter@gmail.com>
Co-authored-by: Emmanuel Evance <mtuchidev@gmail.com>

* fhir: map primitive elements (#1678)

* feat: implement primitive mappings

Signed-off-by: Hunter Achieng <achienghunter@gmail.com>

* feat: update comments

Signed-off-by: Hunter Achieng <achienghunter@gmail.com>

* fix tests

Signed-off-by: Hunter Achieng <achienghunter@gmail.com>

* feat: update fhir-eswatini

Signed-off-by: Hunter Achieng <achienghunter@gmail.com>

* fix: remove skipped tests

Signed-off-by: Hunter Achieng <achienghunter@gmail.com>

* feat: fix primp value renaming

Signed-off-by: Hunter Achieng <achienghunter@gmail.com>

* fix: package.json

Signed-off-by: Hunter Achieng <achienghunter@gmail.com>

* feat: rebuild fhir-eswatini

Signed-off-by: Hunter Achieng <achienghunter@gmail.com>

* fix: remove nested `_birthTime`

Signed-off-by: Hunter Achieng <achienghunter@gmail.com>

* fix: add tests

Signed-off-by: Hunter Achieng <achienghunter@gmail.com>

* clean up tests

* remove comment

* fix: add tests and update docs

Signed-off-by: Hunter Achieng <achienghunter@gmail.com>

* bump fhir-gen tool

* fhir-eswatini: update build meta

* changeset

---------

Signed-off-by: Hunter Achieng <achienghunter@gmail.com>
Co-authored-by: Joe Clark <joe@openfn.org>

* versions

---------

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Hunter Achieng <achienghunter@gmail.com>
Co-authored-by: Pius Kariuki <39379012+PiusKariuki@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: hunterachieng <79210550+hunterachieng@users.noreply.github.com>
Co-authored-by: Emmanuel Evance <mtuchidev@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Closed

Development

Successfully merging this pull request may close these issues.

DHIS2: Schema should not require username/password when using a PAT

4 participants