Authentication lost

Hello :wave:

So, I’m in the situation where authentication is up and running but something’s missing. Nothing happens if my session expires, so I may send queries & mutations but I’d struggle to properly handle this - I’d want to be able to prompt my user for a reauth.

I had a look at the AuthProvider wondering if there could be a solution, since the app is calling __REDWOOD__AUTH_GET_CURRENT_USER pretty up front, I was somehow expecting to be notified at that point that the reauth was needed. Anyway, I’m not sure how to do it properly and I’m not even sure it’s a clean enough lead.

Has anyone implemented that aspect of session management?

1 Like

Do you protect your services with requireAuth() that is described in this tutorial? I’m not sure what it returns when being unauthenticated, but I guess there is some response from that allowing you to eventually prompt the user in your app for a reauth.

1 Like

Hey @noire.munich!

So I guess there’s two scenarios here:

  1. You’re reloading the entire page and the authentication stack is rebooting and fetching getCurrentUser

If your <Route> is wrapped in <Private unauthenticated=""> it should redirect you to the unauthenticated route.

  1. You’re mid-session and the token expires, so you’re getting a “not authenticated” response from the GraphQL api.

Right now we don’t have a custom-hook for that, but it should be possible to handle with Apollo’s HTTP Links: They allow you to inspect the network traffic for each response. If you get an unauthorized response you’ll be able to reload the window/ or redirect to a different place.

Please let me know if you’re in one of these scenarios, and I can offer some detailed guidance. Or maybe you’re in a 3rd scenario? :astonished:

1 Like

Hi guys and thanks a lot for the answers!

I have indeed and it returns this:

api | AuthenticationError: You don't have permission to do that.

which leads to what @peterp ( hi \o/ ) says here:

That’s exactly what I’d be looking for, hooks to inspect each response. There are the auth issues sent by the graphql api but if we could also isolate undesired detailed exception stacks that would be nice, provided RW helps to identify them.
I am ready for your detailed guidance x)

Ok! So we’re going to do the “quick and dirty” way first - and if this works for you - then we’ll add it into Redwood.

The way to do this with Apollo is to instantiate a new client, and to pass it a link option (docs):

import { ApolloClient, InMemoryCache, HttpLink } from '@apollo/client';
import { onError } from '@apollo/client/link/error';

import { logout } from './logout';

const httpLink = new HttpLink({ uri: '/graphql' });

const logoutLink = onError(({ networkError }) => {
  if (networkError.statusCode === 401) logout();
})

const client = new ApolloClient({
  cache: new InMemoryCache(),
  link: logoutLink.concat(httpLink),
});

But, for Redwood the integration point should be to supply a custom graphql configuration:

// src/index.js


const httpLink = new HttpLink({ uri: '/graphql' });

const logoutLink = onError(({ networkError }) => {
  if (networkError.statusCode === 401) navigate('/login?status=timeout')
})

const config = {
  cache: new InMemoryCache(), // I'm not sure if this is required.
  link: logoutLink.concat(httpLink),
}

return (
<RedwoodProvider graphQLClientConfig={config}>
{...}
</RedwoodProvider>
)

I would call 'logOuton the/login` page to reset the state. Please let me know how this goes, it’s super late and I don’t know if I’ve parsed this code in my brain correctly.

1 Like

Thanks @peterp

Ok I’m trying it out, it’s not yielding many results :-. Since I couldn’t see anything happening I digged a bit more in the doc and got some code from there which looks a lot like yours, a bit “enhanced” though.
I still don’t get results.

Two issues I’ve had:

  • imports from your examples didn’t work, I had to use this:
import { ApolloClient } from 'apollo-client'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { createHttpLink } from 'apollo-link-http'
import { onError } from 'apollo-link-error'
  • I configured an onError link but the outputs I’ve set within it are not being used:

const link = onError(({ graphQLErrors, networkError }) => {
  alert('link works')
  console.log(graphQLErrors, networkError)
  if (graphQLErrors)
    graphQLErrors.forEach(({ message, locations, path }) =>
      console.log(
        `#YOU^FAILED#[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
      )
    )
  if (networkError) console.log(`#YOU^FAILED#[Network error]: ${networkError}`)
})

The #YOU^FAILED# acts as a flag, messages would have been too generic…

Anyway! So this is not outputting anything, I went back to RW source code in packages/web but since the code is super easy I would totally expect the config to be passed down to RW’s ApolloClient as it should.

That’s where I am now, figuring out if I can get some link added to RW’s configuration, covering not only the onError case but also other links.

I knew nothing about them but there are also the awesome rest link, context and retry, would be sweet to be able to tap into these :).

I’ll keep you posted if anything comes up! Meanwhile if you could space a couple of minutes to try something it would be great.

Last but not least: the cache doesn’t seem to be required but the doc sells it fairly: https://www.apollographql.com/docs/react/why-apollo/#zero-config-caching

I think it could deserve a note in RW’s doc, do you think it’s relevant?

Just a small update that I’ll get to this tomorrow :bowing_man:‍♂, sorry for the delay!

2 Likes