Initial commit

This commit is contained in:
phil 2025-01-25 02:23:43 +01:00
commit 80f742675a
12 changed files with 5508 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
node_modules/*
dist/*

3
Containerfile Normal file
View file

@ -0,0 +1,3 @@
FROM docker.io/nginx:alpine
COPY ./dist /usr/share/nginx/html

21
README.md Normal file
View file

@ -0,0 +1,21 @@
# Test app for OIDC, OAuth2 - pure web client version written with Vue3
Small web app for experimenting a web app with a Keycloak auth server.
## Deployment
In a container:
```sh
pnpm run build --base oidc-test-web
podman run -it --rm -p 8874:80 -v ./dist:/usr/share/nginx/html/oidc-test-web docker.io/nginx:alpine
```
## Frontend
```Caddyfile
handle /iodc-test-web {
reverse-proxy hostname.domainame:8874
}
redir /oidc-test-web /oidc-test-web/
```

12
index.html Normal file
View file

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Axios interceptor example</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

3225
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

29
package.json Normal file
View file

@ -0,0 +1,29 @@
{
"name": "typescript",
"version": "0.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite --port 3000",
"build": "run-p type-check \"build-only {@}\" --",
"preview": "vite preview",
"build-only": "vite build",
"type-check": "vue-tsc --build"
},
"dependencies": {
"@dsb-norge/vue-keycloak-js": "3.0.1",
"axios": "1.7.9",
"vue": "3.5.13"
},
"devDependencies": {
"@tsconfig/node22": "22.0.0",
"@types/node": "22.10.5",
"@vitejs/plugin-vue": "5.2.1",
"@vue/tsconfig": "0.7.0",
"npm-run-all2": "7.0.2",
"typescript": "5.6.3",
"vite": "6.0.7",
"vite-plugin-vue-devtools": "7.7.0",
"vue-tsc": "2.2.0"
}
}

2087
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load diff

40
src/App.vue Normal file
View file

@ -0,0 +1,40 @@
<script setup lang="ts">
import { HTTP } from '@/main'
import type { AxiosResponseHeaders } from 'axios'
import { ref } from 'vue'
import { useKeycloak } from '@dsb-norge/vue-keycloak-js'
const keycloak = useKeycloak()
const requestHeaders = ref<AxiosResponseHeaders | Partial<unknown> | undefined>()
function manuallyRefreshAccessToken() {
// We set a high minValidity to force a token refresh
keycloak.keycloak && keycloak.keycloak.updateToken(5000)
}
async function doAuthenticatedRequest() {
// Doesn't really go anywhere, but as you see from the headers in the request
// it contains the latest access token at all times
const response = await HTTP.get('/oidc-test-web')
requestHeaders.value = response.config.headers
}
</script>
<template>
<h1>OIDC pure web client test</h1>
<div>
<div>Hey {{ keycloak?.fullName }}</div>
<button @click="doAuthenticatedRequest">Trigger request</button>
<button @click="manuallyRefreshAccessToken">Refresh access token</button>
<div>
<textarea :value="requestHeaders?.toString()" readonly></textarea>
</div>
</div>
</template>
<style scoped>
textarea {
width: 100%;
height: 30vh;
}
</style>

37
src/main.ts Normal file
View file

@ -0,0 +1,37 @@
import { createApp } from 'vue'
import Keycloak from "keycloak-js"
import VueKeycloakJs, { useKeycloak } from '@dsb-norge/vue-keycloak-js'
import axios from 'axios'
import App from './App.vue'
export const HTTP = axios.create({
baseURL: '/',
timeout: 10_000
})
function initializeTokenInterceptor() {
HTTP.interceptors.request.use(config => {
const keycloak = useKeycloak()
if (keycloak.authenticated) {
config.headers.Authorization = `Bearer ${keycloak.token}`
}
return config
}, error => {
return Promise.reject(error)
})
}
createApp(App)
.use(VueKeycloakJs, {
config: {
url: 'https://philo.ydns.eu/auth/',
realm: 'test',
clientId: 'oidc-test-web',
},
onReady(kk: Keycloak, vkk) {
//console.log(kk, vkk)
console.log(kk.idTokenParsed)
initializeTokenInterceptor()
},
})
.mount('#app')

12
tsconfig.app.json Normal file
View file

@ -0,0 +1,12 @@
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
"exclude": ["src/**/__tests__/*"],
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"paths": {
"@/*": ["./src/*"]
}
}
}

11
tsconfig.json Normal file
View file

@ -0,0 +1,11 @@
{
"files": [],
"references": [
{
"path": "./tsconfig.node.json"
},
{
"path": "./tsconfig.app.json"
}
]
}

29
vite.config.ts Normal file
View file

@ -0,0 +1,29 @@
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import fs from 'fs';
import path from 'path';
import vue from '@vitejs/plugin-vue'
import vueDevTools from 'vite-plugin-vue-devtools'
// https://vite.dev/config/
export default defineConfig({
plugins: [
vue(),
vueDevTools(),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
},
},
server: {
https: {
// key: fs.readFileSync(path.resolve(__dirname, 'localhost-key.pem')),
// cert: fs.readFileSync(path.resolve(__dirname, 'localhost.pem')),
key: fs.readFileSync(path.resolve("/home/phil", 'tiptop+4-key.pem')),
cert: fs.readFileSync(path.resolve("/home/phil", 'tiptop+4.pem')),
},
}
})