Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Authenticate with nmdc-server backend #26

Merged
merged 12 commits into from
Feb 9, 2024
Merged

Conversation

pkalita-lbl
Copy link
Collaborator

Fixes microbiomedata/issues#561

These changes rely on the changes from microbiomedata/nmdc-server#1130. I'm keeping this in draft until those changes are merged and I can test authentication against the dev nmdc-server instance.

New dependencies

@capacitor/browser is added in order to open a browser window to initiate the login process.

Making authenticated API requests

The src/api.ts module has been refactored a bit to support making API requests using a bearer token in the Authorization header. Previously this module exported individual, stateless request-making functions. However we now have a bit of stateful-ness: sometimes the application will have an API token and sometimes it will not depending on your login state.

I chose to reimplmenent this as sort of a object-oriented singleton pattern. There is a base FetchClient class which wraps calls to fetch and knows how to provide the bearer token if you give it one. The NmdcServerClient inherits from FetchClient and defines methods to request specific endpoints. One instance of NmdcServerClient is created and exported by the module. The state of this single instance can be updated (by calling the setBearerToken method) as login or logout events happen.

Application data store

The src/Store.tsx module sets up a new React context that can be used to get and set (possibly in persistent storage) arbitrary application data. For now it's just holding the API token string. It also provides access to the underlying persistent storage object. It exports a StoreProvider component and a hook to access the context value.

When the StoreProvider component is initialized, it sets up the persistent Storage object and checks to see if there is an API token there. If it finds one it uses that value to update its in-memory state (in order to rerender anything that depends on it) and the NmdcServerClient singleton instance. The same things happen when calling the exported setApiToken function, plus updating the value in persistent storage.

Query provider updates

Previously the TanStack Query provider was set up along with the persistent storage object in src/App.tsx. This has been refactored into a separate component (src/QueryClientProvider.tsx). Instead of setting up a Storage object itself, this component makes use of the useStore hook exported by src/Store.tsx to get the Storage object it needs for persisting API data.

With the new StoreProvider and QueryClientProvider components, I also took the opportunity to move the routing setup into a separate Routes component (src/Routes.tsx). This allows src/App.tsx to be radically simplified.

New routes

First there is a new Route wrapper component called AuthRoute (src/components/AuthRoute/AuthRoute.tsx) which uses the useStore hook to access the API token. If it is null it redirects the user to a new /login route, otherwise it renders just like a normal Route. This is based on ideas from https://v5.reactrouter.com/web/example/auth-workflow. We're using react-router v5 because Ionic doesn't support v6 yet (ionic-team/ionic-framework#24177).

The new /login route displays src/pages/LoginPage/LoginPage.tsx which is a very un-pretty page directing the user to login along with a button to initiate the login process.

When the login process completes, nmdc-server will link back into the /token route. The src/pages/TokenPage/TokenPage.tsx page simply extracts the token from the redirect URL, uses setApiToken provided by useStore, and redirects the user to the /home route. The /home route is now protected as an AuthRoute.

Finally the /logout route displays src/pages/LogoutPage/LogoutPage.tsx which uses setApiToken provided by useStore to clear the API token and redirect back to the root route.

This replaces the standalone API request functions with an NmdcServerClient class with equivalent methods. A singleton instance of this class is constructed and exported. This allows an API token to be set on this instance and all subsequent requests will use that token.

These changes also add a new method for calling the `/api/me` endpoint to retrieve the current user.
The Login page has a button that initiates the nmdc-server login using the @capacitor/browser plugin and a new environment variable for the server login route.

The Token page is where the backend will redirect to on successful login with the API token in a query parameter. This page collects that token, places it in persistent storage, and redirects to the home page.

The Logout page clears the token from persistent storage and redirects to the root page.
These changes wrap the main application in the new StoreProvider. The TanStack query setup has also been moved to a dedicated component so that it can use the `useStore` hook to access the store while setting up its persistence layer. Finally, the routing has also moved to a separate component where it also uses the `useStore` hook in order to decide where to redirect the root route.

A new AuthRoute component has been added that can be used when registering routes that a user must be logged in (as determined by having an API token in the store) to view.
This is mainly for demo purposes and can be removed later
@eecavanna
Copy link
Collaborator

I haven't looked at the diff yet, but I have read the PR description and thought that was great! 👏

Copy link
Collaborator

@yxu-lanl yxu-lanl left a comment

Choose a reason for hiding this comment

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

Thanks.

Copy link
Collaborator

@eecavanna eecavanna left a comment

Choose a reason for hiding this comment

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

Looks great! Thanks for implementing this and for documenting it so clearly and thoroughly.

src/Store.tsx Outdated Show resolved Hide resolved
src/api.ts Outdated Show resolved Hide resolved
src/pages/TokenPage/TokenPage.tsx Show resolved Hide resolved
src/App.tsx Outdated Show resolved Hide resolved
@eecavanna eecavanna added the enhancement New feature or request label Feb 8, 2024
@pkalita-lbl pkalita-lbl marked this pull request as ready for review February 9, 2024 00:30
@pkalita-lbl pkalita-lbl merged commit 64e8b6b into main Feb 9, 2024
1 check passed
@pkalita-lbl pkalita-lbl deleted the issue-561-nmdc-server-auth branch February 9, 2024 00:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
Development

Successfully merging this pull request may close these issues.

Make authenticated request to nmdc-server from field notes app
3 participants