Initial commit
This commit is contained in:
commit
80f742675a
12 changed files with 5508 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
node_modules/*
|
||||
dist/*
|
3
Containerfile
Normal file
3
Containerfile
Normal file
|
@ -0,0 +1,3 @@
|
|||
FROM docker.io/nginx:alpine
|
||||
|
||||
COPY ./dist /usr/share/nginx/html
|
21
README.md
Normal file
21
README.md
Normal 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
12
index.html
Normal 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
3225
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
29
package.json
Normal file
29
package.json
Normal 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
2087
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load diff
40
src/App.vue
Normal file
40
src/App.vue
Normal 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
37
src/main.ts
Normal 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
12
tsconfig.app.json
Normal 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
11
tsconfig.json
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.node.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.app.json"
|
||||
}
|
||||
]
|
||||
}
|
29
vite.config.ts
Normal file
29
vite.config.ts
Normal 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')),
|
||||
},
|
||||
}
|
||||
})
|
Loading…
Add table
Add a link
Reference in a new issue