How to set cookies from `.htaccess` & how to access the auth header from a single page application, or static site.
Ismael Garcia
Posted on March 26, 2024
How to set cookies from .htaccess
and how to access the auth header from a single page application, or static site.
What is the use case for this ?
You have a single page application, that need to use the auth token to handle, CRUD operations.
But this application needs to be embedded on a mobile application, that will render the web application in a View with in the application.
But when they load the single page application they pass an auth header, but your application is a single page application, and you don’t have a service like Back-end For Front-end (BFF).
So one of the solutions, for this problem can be that you access the auth header from the
.htaccess
or nginx config and set cookies base on the value of the header.
For my use case, we are using Apache web server, so the .htaccess
is the solution for this until we have a BFF.
Let’s start the implementation
From the .htaccess
- [x] Check if there is auth header
# Extract Authorization header value
RewriteCond %{HTTP:Authorization} ^Bearer\s+(.+)$ [NC]
- [x] Extract the auth header token
# Set the value for the AUTH_TOKEN
RewriteRule .* - [E=AUTH_TOKEN:%1]
- [x] Create a cookie and save the cookie with the token value
# Set the cookie base on the header auth
Header set Set-Cookie "TOKEN_CONTAINER=%{AUTH_TOKEN}e; Path=/" env=AUTH_TOKEN
Here is the final code for it:
# Extract Authorization header value
RewriteCond %{HTTP:Authorization} ^Bearer\s+(.+)$ [NC]
RewriteRule .* - [E=AUTH_TOKEN:%1]
Header set Set-Cookie "TOKEN_CONTAINER=%{AUTH_TOKEN}e; Path=/" env=AUTH_TOKEN
Note:
***Remember that to access the auth header token the Access-Control-Allow-Origin
need to be set it to the origin of the call
The Access-Control-Allow-Origin
can’t be "*"
base on this from MDN.
Credential is not supported if the CORS header 'Access-Control-Allow-Origin' is '*'
So you need to set the Access-Control-Allow-Origin
to the actual domain name that you need, for example you can set the Access-Control-Allow-Origin
as "*"
for other routes and just filter a specific route that you need to access the auth header
Example:
# Set CORS header for /path-need-cors path
RewriteCond %{REQUEST_URI} ^/path-need-cors [NC]
RewriteRule .* - [E=CORS_ORIGIN:https://domainname.com]
# Set CORS header based on the determined origin
Header always set Access-Control-Allow-Origin "%{CORS_ORIGIN}e" env=CORS_ORIGIN
# Set CORS header if the CORS_ORIGIN variable is undefined or not set
Header always set Access-Control-Allow-Origin "*" env=!CORS_ORIGIN
Header always set Vary "Origin"
Header always set Access-Control-Allow-Headers "Accept, Accept-Encoding, Authorization, Content-Type, DNT, Origin, User-Agent, X-Requested-With"
Header always set Access-Control-Allow-Methods "GET, POST, OPTIONS"
Header always set Access-Control-Allow-Credentials "true"
Step 2 in this example I’m using Vue
Now that you set the cookie on the .htaccess
- [x] Check if the cookie have a value from JavaScript
- [x] extract the token value
- [x] Use the token to load user information
<script lang="ts" setup>
/**
*
* Load cookie and check the value then call the user info with the provided token
*
* @author Leamsigc <Ismael Garcia>
* @version 0.0.1
*
* @todo [ ] Test the component
* @todo [ ] Integration test.
* @todo [✔] Update the typescript.
*/
//...other imports.
import { useCookies } from '@vueuse/integrations/useCookies';
const cookies = useCookies();
const COOKIE_TOKEN = ref(cookies.get('TOKEN_CONTAINER') as string);
const { state, actions } = useOidcStore();
//Delete cookie after accessing the value of it.
cookies.remove('TOKEN_CONTAINER');
if (COOKIE_TOKEN.value) {
const request = await AuthUserService.loadUserInformation({ refreshToken: COOKIE_TOKEN.value });
if (request.status === 200) {
request.data ? actions.value.setUser(new User(request.data as any)) : null;
}
}
</script>
<template>
<SuspenseWrapper>
<template v-if="loading === 'success'">
<UserComponent :component-key="'MyUserProfile'" />
</template>
<template v-else-if="loading === 'error'">
<ErrorView @close-trigger="loading = 'idle'" />
</template>
<template v-else>
<h2>Handle other use case</h2>
</template>
</SuspenseWrapper>
</template>
<style scoped></style>
NOTE:
I’m using oidc-client-ts
, so accessing the token help me to manually refresh the token and then set the value of the user in the oidc-client-ts
storage and that manage the refresh of the user token on the single page application.
I can provide an example if anyone have questions.
Can someone submit this article to the Daily dev, I can't do my self no enough reputation just 10 at the moment
Posted on March 26, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.