There are cases where a service will have to call a third-party api on behalf of the currentUser.
One case is Netlify Identity.
Consider this service that wants to update a user’s user_metadata
(where profile info and preferences can be store). It makes PUT
request to Netlify Identity to update that user_metadata.
import { context } from '@redwoodjs/api/dist/globalContext'
import got from 'got'
import { requireAuth } from 'src/lib/auth'
export const userMetadata = () => {
requireAuth()
return context.currentUser.user_metadata
}
export const updateUserMetadata = async ({ input }) => {
requireAuth()
const { body } = await got.put(
'https://MYAPP.netlify.app/.netlify/identity/user',
{
responseType: 'json',
json: {
data: {
...input,
},
},
headers: {
authorization: `Bearer ${NEED_ACCESS_TOKEN_HERE}`,
},
}
)
context.currentUser.user_metadata = body.user_metadata
return context.currentUser.user_metadata
}
But right now there is no great way to get NEED_ACCESS_TOKEN_HERE
.
It is not on the context
. In getCurrentUser
grpahql passes along the event which has the headers and the type, schema, and token for is extracted:
/**
* Split the `Authorization` header into a schema and token part.
*/
export const parseAuthorizationHeader = (
event: APIGatewayProxyEvent
): AuthorizationHeader => {
const [schema, token] = event.headers?.authorization?.split(' ')
if (!schema.length || !token.length) {
throw new Error('The `Authorization` header is not valid.')
}
// @ts-expect-error
return { schema, token }
}
Looking for ideas where best to keep the accessToken.
My current workaround is to store it on the currentUser
:
export const getCurrentUser = async (decoded, { token, type }) => {
const authorization = { token, type }
return { ...decoded, roles: parseJWT({ decoded }).roles, authorization }
}
But would rather it be available perhaps on the context as done in graphql
:
// If the request contains authorization headers, we'll decode the providers that we support,
// and pass those to the `currentUser`.
const authContext = await getAuthenticationContext({ event, context })
if (authContext) {
context.currentUser = getCurrentUser
? await getCurrentUser(authContext[0], authContext[1])
: authContext
}
let customUserContext = userContext
if (typeof userContext === 'function') {
// if userContext is a function, run that and return just the result
customUserContext = await userContext({ event, context })
}
@peterp I have not seen customUserContext
implemented before, might the token be stored there?
Anyone have ideas?
Cheers.