kit icon indicating copy to clipboard operation
kit copied to clipboard

Pass 'Authorization' header to next authorized page, no use of cookies

Open d-adamkiewicz opened this issue 3 years ago • 8 comments

Describe the problem

Hi, I'm curious if it's possible. After successful redirect to say /admin page where there is a menu of linked subpages and click on each link will cause subpage receive 'Authorization' request header accessible in load() BUT without use of cookies ?

Describe the proposed solution

I'm stuck.

Alternatives considered

No response

Importance

nice to have

Additional Information

No response

d-adamkiewicz avatar Dec 20 '22 13:12 d-adamkiewicz

Can you elaborate on how the exact flow would look like?

I assume the redirect results in a full page reload and the html response carries the Authorization header. I´m pretty sure there is no way to forward any headers to another request. Cookies are made for that use case and i´m curious why you can´t use them

david-plugge avatar Dec 20 '22 17:12 david-plugge

something like this would be useful, Essential Azure Graph API needs auth_token to retrieve the user's profile picture

<a href="/dashboard/accounts" header={Authorization: Bearer <token>} >accounts</a>
<img src="https://graph.microsoft.com/v1.0/me/photos/48x48" header={Authorization: Bearer <token>}>

xmlking avatar Dec 20 '22 18:12 xmlking

Other Option: hooks.client.ts should support handleFetch similar to hooks.server.ts

then we can define fetch intercepter like this

export const handleFetch: HandleFetch = async ({ event, request, fetch }) => {
	const { locals } = event;

	if (request.url.startsWith('https://graph.microsoft.com')) {
		if (locals.token) {
			request.headers.set('Authorization', `Bearer ${locals.token}`);
		}
	}
	
	return fetch(request);
};

xmlking avatar Dec 20 '22 18:12 xmlking

@david-plugge Why? Because you cannot set cookies in a browser in LAN. Let assume route /admin?q=123 where q is some sort of session id, using +server.js + +page.server.js I can pass header to load() but I cannot catch GET parameter

// admin/+server.js
export async function GET({ url }) {
  // <host>/admin?q=123
  // null !!!, you cannot catch 'q' !!!
  console.log(url.searchParams.get('q'));
  let a = 1;
  return new Response(JSON.stringify({ a }), {
    headers: {
      'Content-Type': 'application/json',
// examplary
      Authorization: 'Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ'
    }
  });
}
// admin/+page.server.js
export async function load({ fetch, locals }) {
  const response = await fetch("/admin");
  console.log('load()', response.headers.get("authorization"));
  const a = await response.json();
  return a;
}
// admin/+page.svelte
<script>
  export let data;
</script>

<h1>+page.svelte</h1>
{#if data?.a}
  {data.a}
{/if}

Please let me know if this is understandable.

d-adamkiewicz avatar Dec 20 '22 20:12 d-adamkiewicz

Well you are fetching /admin. Try passing the query param along like /admin?q=${sessionId} in fetch inside load

david-plugge avatar Dec 21 '22 15:12 david-plugge

If you expect to always have the query param you can also use the handleFetch hook to always attach the param to the request url

david-plugge avatar Dec 21 '22 15:12 david-plugge

@xmlking

I don't think a header attribute would be possible for anchor tags without using JS, and straight-out impossible for media since fetching them is handled by the browser. I would just store the auth token in a cookie and implement an endpoint (like /api/user-pfp.jpg) that fetches and returns the image using the stored token. Or, you can just fetch the image in a load function and use the blob directly.

pilcrowonpaper avatar Dec 23 '22 17:12 pilcrowonpaper

@david-plugge - it seems to me that url.searchParams.get(...) worked for API routes in previous version of SvelteKIt (it was named in lowercase ie get() then question if this change is non-reversible ?), it is quite crucial for query string parameter be accessible in GET() because value of Authorization header value can be decoded here and say check if q is valid session id.

d-adamkiewicz avatar Dec 24 '22 16:12 d-adamkiewicz

The code in question doesn't pass along the query param as David pointed out. This should work:

// admin/+page.server.js
export async function load({ fetch, locals, url }) {
  const response = await fetch("/admin?q=" + url.searchParams.get('q')); // forward query param
  console.log('load()', response.headers.get("authorization"));
  const a = await response.json();
  return a;
}
// admin/+server.js
export async function GET({ url }) {
  console.log(url.searchParams.get('q')); // should be defined
  let a = 1;
  return new Response(JSON.stringify({ a }), {
    headers: {
      'Content-Type': 'application/json',
// examplary
      Authorization: 'Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ'
    }
  });
}

As for the other feature request, handleFetch for the client side is tracked in #6734

dummdidumm avatar Jan 13 '23 13:01 dummdidumm