---
# System prepended metadata

title: 'Refresh token logic, pt - Fri 9th Oct, 2020'
tags: [C+, reactivevariables, errorLink, programmingjournal, '2020', apolloclient, refreshtoken, auth]

---

# Refresh token logic, pt - Fri 9th Oct, 2020

[Continuing yesterday's entry](https://hackmd.io/EpngQeERQxm1U2X65gBvVw), I finished adding the setup to "refresh" an expired access token:

```typescript=
if (
    networkError &&
    'statusCode' in networkError &&
    (networkError.statusCode === 401)
) {
    console.log(`[Network error ${operation.operationName}]: ${networkError!.message}`)
    return new Observable((observer) => {
        SecureStrage.get('refresh_token').then((refreshToken) => {
            if (refreshToken) {
                getNewTokens()
                    .then((refreshResponse) => {
                        // got new tokens, save to secure storage
                        Promise.all([
                            SecureStrage.set('access_token', refreshResponse.access_token),
                            SecureStrage.set('refresh_token', refreshResponse.refresh_token),
                        ])
                            .then(() => {
                                // tokens set to storage, swap out headers
                                operation.setContext(({ headers = {} }: { headers: Record<string, string> }) => ({
                                    headers: {
                                        // Re-add old headers
                                        ...headers,
                                        // Switch out old access token for new one
                                        authorization: refreshResponse.access_token || null,
                                    },
                                }))
                                const subscriber = {
                                    next: observer.next.bind(observer),
                                    error: observer.error.bind(observer),
                                    complete: observer.complete.bind(observer),
                                }
                                // Retry last failed request
                                forward(operation).subscribe(subscriber)
                            })
                            .catch((error) => {
                                // No refresh or client token available, we force user to login
                                observer.error(error)
                                console.log('Error setting to storage: ', error)
                                logOut('error')
                            })
                    })
                    .catch((error) => {
                        crashlytics().recordError(error)
                        console.log('Something went wrong with Identity refresh: ', error)
                        logOut('error')
                    })
            } else if (!refreshToken) {
                crashlytics().log('No refresh token. Logging user out')
                console.log('No refresh token. Logging user out')
                logOut('error')
            }
        })
    })
}
```

As discussed yesterday, in order to update the auth status from within `onLink`, I used an Apollo reactive var, wrapped in a hook for easy use within React components:

```typescript=
export type AuthStatusQuery = { authStatus: AuthStatus }

export const GET_AUTH_STATUS = gql`
    query getAuthStatus {
        authStatus @client
    }
`

export const useAuthStatus = (): [AuthStatus, ReactiveVar<AuthStatus>] => {
    const { data } = useQuery<AuthStatusQuery>(GET_AUTH_STATUS)
    const setAuthStatus = useCallback(authenticate, [])
    return [data?.authStatus ?? 'unknown', setAuthStatus]
}
```

You could see reactive vars being very useful for things you might have previously used React Context for such as a flag to say if an app's hamburger menu is open.

###### tags: `programmingjournal` `2020` `C+` `auth` `reactivevariables` `apolloclient` `refreshtoken` `errorLink`