-
Notifications
You must be signed in to change notification settings - Fork 0
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
Conversation
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
I haven't looked at the diff yet, but I have read the PR description and thought that was great! 👏 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks.
There was a problem hiding this 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.
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 theAuthorization
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 tofetch
and knows how to provide the bearer token if you give it one. TheNmdcServerClient
inherits fromFetchClient
and defines methods to request specific endpoints. One instance ofNmdcServerClient
is created and exported by the module. The state of this single instance can be updated (by calling thesetBearerToken
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 aStoreProvider
component and a hook to access the context value.When the
StoreProvider
component is initialized, it sets up the persistentStorage
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 theNmdcServerClient
singleton instance. The same things happen when calling the exportedsetApiToken
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 aStorage
object itself, this component makes use of theuseStore
hook exported bysrc/Store.tsx
to get theStorage
object it needs for persisting API data.With the new
StoreProvider
andQueryClientProvider
components, I also took the opportunity to move the routing setup into a separateRoutes
component (src/Routes.tsx
). This allowssrc/App.tsx
to be radically simplified.New routes
First there is a new
Route
wrapper component calledAuthRoute
(src/components/AuthRoute/AuthRoute.tsx
) which uses theuseStore
hook to access the API token. If it isnull
it redirects the user to a new/login
route, otherwise it renders just like a normalRoute
. This is based on ideas from https://v5.reactrouter.com/web/example/auth-workflow. We're usingreact-router
v5 because Ionic doesn't support v6 yet (ionic-team/ionic-framework#24177).The new
/login
route displayssrc/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. Thesrc/pages/TokenPage/TokenPage.tsx
page simply extracts the token from the redirect URL, usessetApiToken
provided byuseStore
, and redirects the user to the/home
route. The/home
route is now protected as anAuthRoute
.Finally the
/logout
route displayssrc/pages/LogoutPage/LogoutPage.tsx
which usessetApiToken
provided byuseStore
to clear the API token and redirect back to the root route.