Skip to content

refactor: use GDS Internal Access/i.AI Auth API for auth layer#22

Merged
RyanWhite25 merged 28 commits into
mainfrom
refactor/auth_api_migration
Jan 10, 2026
Merged

refactor: use GDS Internal Access/i.AI Auth API for auth layer#22
RyanWhite25 merged 28 commits into
mainfrom
refactor/auth_api_migration

Conversation

@RyanWhite25

Copy link
Copy Markdown
Contributor

DO NOT MERGE => this change incurs a small amount of downtime and significant UX change, and needs to be carried out in a controlled way.

This change migrates away from i.AI keycloak as the authentication layer, using GDS Internal Access instead.

Authorisation is provided by i.AI's Auth API, instead of inspecting the Keycloak token for claims within the code's middleware/DI layer.

Core code changes:

  • i.AI utilities libraries offload token verification and app authorisation checks to an external Auth API - this is for both the frontend middleware and the backend routes via UserDep.
  • Terraform updated to utilise GDS Internal Access clients
  • Structured Logger instantiated in the backend for use with the auth library (it's not replacing the python logger anywhere else - these two loggers exist in parallel for now)
  • Generic error page added to the frontend to catch any middleware errors and provide a reasonable UX if anything goes wrong during the auth process
  • The frontend middleware has been refactored to i) exclude more public paths that don't require auth and ii) proxy requests to the backend before the frontend auth logic is executed. This is to reduce the amount of redundant calls to the auth API, as the /api/proxy requests are recursively invoking the middleware. @i-dot-ai/minute-admins could you validate this change in particular please? All backend routes implement UserDep, so I don't see why we need to go through the frontend auth flow for these.

@RyanWhite25 RyanWhite25 requested a review from a team as a code owner November 13, 2025 10:45
Comment thread frontend/middleware.ts Outdated
@@ -1,50 +1,71 @@
import { isAuthorisedUser } from '@/lib/auth'

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.

This import isn't used anymore, and that whole lib/auth can be deleted now

Comment thread frontend/middleware.ts
Comment on lines +12 to +14
'/monitoring',
'/privacy',
'/support',

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.

We don't have a monitoring page, and can you remove /privacy and /support from the public urls for now?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I've kept these in as we discussed on Slack - somethign is hitting /monitoring, and the other pages will continue to be behind GDS Internal Access authentication. It saves us making calls to the auth api for pages that don't require it

authorization = jwt.encode(jwt_dict, "secret", algorithm="HS256", headers=jwt_headers)
authorization: str | None = x_amzn_oidc_data

if not authorization:

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.

This isn't working for me locally because the frontend doesn't pass a fake auth header to the backend. We need to always load the dummy data locally, and skip this check for the header

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for spotting this, I've refactored to do this check after the check to see if the backend is running in a local environment.

Comment thread terraform/ecs.tf
environment_variables = merge(local.shared_environment_variables, {
"APP_NAME" : "${local.name}-backend"
"APP_NAME" : "${local.name}-backend",
"AUTH_API_URL" : data.aws_ssm_parameter.auth_api_invoke_url.value,

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.

This needs to be added to the shared_environment_variables even though the worker doesn't use it because the Settings class is shared across both services (or you can stick a placeholder in the worker)

It's something I'd like to change in future

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Doing this means that we'll also need to pass shared_environment_variables into the frontend - currently this doesn't happen. Is there any issue with doing this?

For now I've pushed a commit up where we explicitly pass the var in as "unused" for the worker. Happy to go either way, but didn't want to add shared vars to the frontend without checking first as presumably there's a reason for that.

@RyanWhite25 RyanWhite25 merged commit f952a42 into main Jan 10, 2026
23 checks passed
@RyanWhite25 RyanWhite25 deleted the refactor/auth_api_migration branch January 10, 2026 08:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants