├── public
├── favicon.ico
└── index.html
├── src
├── assets
│ └── logo.png
├── main.js
├── views
│ ├── Home.vue
│ ├── Unauthorized.vue
│ └── Secured.vue
├── plugins
│ └── authentication.js
├── App.vue
├── components
│ └── HelloWorld.vue
└── router
│ └── index.js
├── babel.config.js
├── .gitignore
├── README.md
└── package.json
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davetrux/vue-keycloak-demo/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davetrux/vue-keycloak-demo/HEAD/src/assets/logo.png
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/cli-plugin-babel/preset'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 |
6 | # local env files
7 | .env.local
8 | .env.*.local
9 |
10 | # Log files
11 | npm-debug.log*
12 | yarn-debug.log*
13 | yarn-error.log*
14 | pnpm-debug.log*
15 |
16 | # Editor directories and files
17 | .idea
18 | .vscode
19 | *.suo
20 | *.ntvs*
21 | *.njsproj
22 | *.sln
23 | *.sw?
24 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import App from './App.vue'
3 | import router from './router'
4 | import authentication from "@/plugins/authentication"
5 |
6 | Vue.config.productionTip = false
7 | Vue.use(authentication)
8 |
9 | Vue.$keycloak
10 | .init({ checkLoginIframe: false })
11 | .then(() => {
12 | new Vue({
13 | router,
14 | render: h => h(App)
15 | }).$mount('#app')
16 | })
17 |
--------------------------------------------------------------------------------
/src/views/Home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |

4 |
5 |
6 |
7 |
8 |
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vue-keycloak-demo
2 |
3 | ## Project setup
4 | ```
5 | npm install
6 | ```
7 |
8 | ### Compiles and hot-reloads for development
9 | ```
10 | npm run serve
11 | ```
12 |
13 | ### Compiles and minifies for production
14 | ```
15 | npm run build
16 | ```
17 |
18 | ### Lints and fixes files
19 | ```
20 | npm run lint
21 | ```
22 |
23 | ### Customize configuration
24 | See [Configuration Reference](https://cli.vuejs.org/config/).
25 |
--------------------------------------------------------------------------------
/src/plugins/authentication.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Keycloak from 'keycloak-js'
3 |
4 | const options = {
5 | url: 'http://localhost:8001/auth/',
6 | realm: 'local-dev',
7 | clientId: 'vue-demo'
8 | }
9 |
10 | const _keycloak = Keycloak(options)
11 |
12 | const Plugin = {
13 | install(Vue) {
14 | Vue.$keycloak = _keycloak
15 | }
16 | }
17 |
18 | Plugin.install = Vue => {
19 | Vue.$keycloak = _keycloak
20 | Object.defineProperties(Vue.prototype, {
21 | $keycloak: {
22 | get() {
23 | return _keycloak
24 | }
25 | }
26 | })
27 | }
28 |
29 | Vue.use(Plugin)
30 |
31 | export default Plugin
32 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | <%= htmlWebpackPlugin.options.title %>
9 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Home |
5 | Secured
6 |
7 |
8 |
9 |
10 |
11 |
41 |
--------------------------------------------------------------------------------
/src/views/Unauthorized.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Unauthorized
4 |
Hello {{ firstName }} {{ lastName }}
5 |
Your account does not have access to that page.
6 |
7 |
8 |
9 |
10 |
32 |
33 |
36 |
--------------------------------------------------------------------------------
/src/views/Secured.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Secure Content
4 |
Hello {{ firstName }} {{ lastName }}
5 |
This page is secured by Keycloak
6 |
7 |
8 |
9 |
10 |
32 |
33 |
36 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-keycloak-demo",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "serve": "vue-cli-service serve",
7 | "build": "vue-cli-service build",
8 | "lint": "vue-cli-service lint"
9 | },
10 | "dependencies": {
11 | "core-js": "^3.6.5",
12 | "keycloak-js": "^12.0.4",
13 | "vue": "^2.6.11",
14 | "vue-router": "^3.2.0"
15 | },
16 | "devDependencies": {
17 | "@vue/cli-plugin-babel": "~4.5.0",
18 | "@vue/cli-plugin-eslint": "~4.5.0",
19 | "@vue/cli-plugin-router": "~4.5.0",
20 | "@vue/cli-service": "~4.5.0",
21 | "babel-eslint": "^10.1.0",
22 | "eslint": "^6.7.2",
23 | "eslint-plugin-vue": "^6.2.2",
24 | "node-sass": "^4.12.0",
25 | "sass-loader": "^8.0.2",
26 | "vue-template-compiler": "^2.6.11"
27 | },
28 | "eslintConfig": {
29 | "root": true,
30 | "env": {
31 | "node": true
32 | },
33 | "extends": [
34 | "plugin:vue/essential",
35 | "eslint:recommended"
36 | ],
37 | "parserOptions": {
38 | "parser": "babel-eslint"
39 | },
40 | "rules": {}
41 | },
42 | "browserslist": [
43 | "> 1%",
44 | "last 2 versions",
45 | "not dead"
46 | ]
47 | }
48 |
--------------------------------------------------------------------------------
/src/components/HelloWorld.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{ msg }}
4 |
5 | Clicked the link above marked "Secured" to see the content blocked by authorization.
6 |
7 |
Use the login button below to force a login before attempting to see the secured content
8 |
9 |
10 |
11 |
12 |
13 |
36 |
37 |
38 |
54 |
--------------------------------------------------------------------------------
/src/router/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import VueRouter from 'vue-router'
3 | import Home from '../views/Home.vue'
4 |
5 | Vue.use(VueRouter)
6 |
7 | const routes = [
8 | {
9 | path: '/',
10 | name: 'Home',
11 | component: Home,
12 | meta: {
13 | isAuthenticated: false
14 | }
15 | },
16 | {
17 | path: '/secured',
18 | name: 'Secured',
19 | meta: {
20 | isAuthenticated: true
21 | },
22 | component: () => import('../views/Secured.vue')
23 | },
24 | {
25 | path: '/unauthorized',
26 | name: 'Unauthorized',
27 | meta: {
28 | isAuthenticated: false
29 | },
30 | component: () => import('../views/Unauthorized.vue')
31 | }
32 | ]
33 |
34 | const router = new VueRouter({
35 | mode: 'history',
36 | base: process.env.BASE_URL,
37 | routes
38 | })
39 |
40 | router.beforeEach((to, from, next) => {
41 | if (to.meta.isAuthenticated) {
42 | // Get the actual url of the app, it's needed for Keycloak
43 | const basePath = window.location.toString()
44 | if (!Vue.$keycloak.authenticated) {
45 | // The page is protected and the user is not authenticated. Force a login.
46 | Vue.$keycloak.login({ redirectUri: basePath.slice(0, -1) + to.path })
47 | } else if (Vue.$keycloak.hasResourceRole('vue-demo-user')) {
48 | // The user was authenticated, and has the app role (is authorized). Update the token.
49 | Vue.$keycloak.updateToken(70)
50 | .then(() => {
51 | next()
52 | })
53 | .catch(err => {
54 | console.error(err)
55 | })
56 | } else {
57 | // The user was authenticated, but did not have the correct role (is not authorized)
58 | // Redirect the user to an error page
59 | next({ name: 'Unauthorized' })
60 | }
61 | } else {
62 | // This page did not require authentication
63 | next()
64 | }
65 | })
66 |
67 | export default router
68 |
--------------------------------------------------------------------------------