Add custom headers for refresh call
Describe the feature
I'd like to be able to send custom headers when nuxt sends a request to the refresh endpoint. Why? Besides sidebase-auth, applications might be protected by Basic Auth (especially during development or staging areas).
Side note: while /refresh does not send the Basic Auth header i setup for my regular api-calls, /getSession does. not sure why.
Would this be of interest? Or is there already a way to achieve this (besides configuring web server setup)?
How would you implement this?
Something like this would be sufficient, although a hook/callback might be more flexible:
// nuxt.config.ts
[...]
refresh: {
isEnabled: true,
endpoint: {
path: 'refresh',
method: 'POST',
headers: {
'Authorization': 'Basic Yml0asFkZW46a3VuZGVuY2VqdGVy',
},
},
[...]
(I replaced the default token.headerName with another header name).
Additional information
- [ ] Would you be willing to help implement this feature?
Provider
- [ ] AuthJS
- [ ] Local
- [X] Refresh
- [ ] New Provider
Hi @n0-m4d , adding hooks for all the methods has been a feature many people anticipate and I personally want to implement.
I did an initial prototype a couple months ago already and wasn't satisfied by it. I would definitely come back to it in the next year, probably for the next minor release even if nothing else pops up :slightly_smiling_face:
I created #964 to gather all the usecases
Hello I see a lot issues on the "custom headers" subject, but no one help me to do what i want.
Is there a way to just add custom headers to endpoint simply like that ?
endpoints: {
signIn: {
path: '/auth/token',
method: 'post',
headers: {
'x-api-key': process.env.API_KEY,
},
},
signOut: false,
signUp: false,
getSession: {
path: '/auth/session',
method: 'get',
headers: {
'x-api-key': process.env.API_KEY,
},
},
},
For signin y do this and it's ok :
await signIn(
{
tmp,
},
{},
{},
{ 'x-api-key': runtimeConfig.public.apiKey }
)
And for getSession i didnt find a workaround.
Did i miss something ?
Thks.
I made a temporary solution by modifying the getSession function of the useAuth.js file
async function getSession(getSessionOptions) {
const nuxt = useNuxtApp();
const config = useTypedBackendConfig(useRuntimeConfig(), "local");
// EDIT
//const { path, method } = config.endpoints.getSession;
const { path, method, headers } = config.endpoints.getSession;
const { data, loading, lastRefreshedAt, rawToken, token: tokenState, _internal } = useAuthState();
let token = tokenState.value;
token ??= formatToken(_internal.rawTokenCookie.value, config);
if (!token && !getSessionOptions?.force) {
loading.value = false;
return;
}
// EDIT
// const headers = new Headers(token ? { [config.token.headerName]: token } : void 0);
let customHeaders = new Headers(token ? { [config.token.headerName]: token } : void 0);
if (headers) {
for (let key in headers) {
customHeaders.append(key, headers[key]);
}
}
loading.value = true;
try {
// EDIT
//const result = await _fetch(nuxt, path, { method, headers });
const result = await _fetch(nuxt, path, { method, headers: customHeaders });
const { dataResponsePointer: sessionDataResponsePointer } = config.session;
data.value = jsonPointerGet(result, sessionDataResponsePointer);
} catch (err) {
if (!data.value && err instanceof Error) {
console.error(`Session: unable to extract session, ${err.message}`);
}
data.value = null;
rawToken.value = null;
}
loading.value = false;
lastRefreshedAt.value = /* @__PURE__ */ new Date();
const { required = false, callbackUrl, onUnauthenticated, external } = getSessionOptions ?? {};
if (required && data.value === null) {
if (onUnauthenticated) {
return onUnauthenticated();
}
await navigateTo(callbackUrl ?? await getRequestURLWN(nuxt), { external });
}
return data.value;
}
And i do the same for refresh :
async function refresh(getSessionOptions) {
const nuxt = useNuxtApp();
const config = useTypedBackendConfig(useRuntimeConfig(), "local");
if (!config.refresh.isEnabled) {
return getSession(getSessionOptions);
}
// EDIT
//const { path, method } = config.refresh.endpoint;
const { path, method, headers } = config.refresh.endpoint;
const refreshRequestTokenPointer = config.refresh.token.refreshRequestTokenPointer;
const { refreshToken, token, rawToken, rawRefreshToken, lastRefreshedAt } = useAuthState();
// EDIT
//const headers = new Headers({
// [config.token.headerName]: token.value
//});
let customHeaders = new Headers({
[config.token.headerName]: token.value
});
if (headers) {
for (let key in headers) {
customHeaders.append(key, headers[key]);
}
}
const response = await _fetch(nuxt, path, {
method,
// EDIT
//headers,
headers: customHeaders,
body: objectFromJsonPointer(refreshRequestTokenPointer, refreshToken.value)
});
const tokenPointer = config.refresh.token.refreshResponseTokenPointer || config.token.signInResponseTokenPointer;
const extractedToken = jsonPointerGet(response, tokenPointer);
if (typeof extractedToken !== "string") {
console.error(
`Auth: string token expected, received instead: ${JSON.stringify(extractedToken)}. Tried to find token at ${tokenPointer} in ${JSON.stringify(response)}`
);
return;
}
if (!config.refresh.refreshOnlyToken) {
const refreshTokenPointer = config.refresh.token.signInResponseRefreshTokenPointer;
const extractedRefreshToken = jsonPointerGet(response, refreshTokenPointer);
if (typeof extractedRefreshToken !== "string") {
console.error(
`Auth: string token expected, received instead: ${JSON.stringify(extractedRefreshToken)}. Tried to find refresh token at ${refreshTokenPointer} in ${JSON.stringify(response)}`
);
return;
}
rawRefreshToken.value = extractedRefreshToken;
}
rawToken.value = extractedToken;
lastRefreshedAt.value = /* @__PURE__ */ new Date();
await nextTick();
return getSession(getSessionOptions);
}