├── LICENSE
├── README.md
├── index.js
├── modules
└── security
│ ├── actions.js
│ ├── getters.js
│ ├── index.js
│ ├── mutations.js
│ └── types.js
├── package.json
└── security
├── header.js
├── index.js
├── init.js
├── logout.js
└── roles.js
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2018-present, Rockt
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | rockt-vuejs-keycloak
2 | =============================================================
3 | Vue.js with Keycloak authentication
4 |
5 | This plugin integrates VueJS with Keycloak to perform authentication and configuration of the authorization to send requests to the backend.
6 |
7 | Requirements
8 | -------------------------------------------------------------
9 | * Vue ^2.0.0
10 | * Vuex ^2.0.0
11 | * axios ^0.17.0
12 |
13 | Installation
14 | -------------------------------------------------------------
15 | ```$ npm install --save rockt-vuejs-keycloak```
16 |
17 | Setup
18 | -------------------------------------------------------------
19 | Put the frontend settings in ```/src/statics/keycloak.json``` file that will be used to authenticate to Keycloak.
20 | ```json
21 | {
22 | "realm": "SERVER-DEV",
23 | "auth-server-url": "https://keycloak.mydomain.com/auth",
24 | "ssl-required": "external",
25 | "resource": "app-name",
26 | "public-client": true,
27 | "use-resource-role-mappings": true,
28 | "confidential-port": 0
29 | }
30 | ```
31 |
32 | Put the plugin at VueJS startup
33 |
34 | ```javascript
35 | // The Vue build version to load with the `import` command
36 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias.
37 | import Vue from 'vue'
38 | import store from 'rockt-vuejs-keycloak'
39 | import App from './App'
40 | import router from './router'
41 |
42 | /* eslint-disable no-new */
43 | new Vue({
44 | el: '#app',
45 | router,
46 | store,
47 | template: '',
48 | components: { App }
49 | })
50 |
51 | ```
52 |
53 | Configure the ```vue-router``` for to use ```rockt-vuejs-keycloak``` on verification of the routes.
54 | ```javascript
55 | import Vue from 'vue'
56 | import VueRouter from 'vue-router'
57 |
58 | import store from 'rockt-vuejs-keycloak'
59 |
60 | import security from 'rockt-vuejs-keycloak/security'
61 |
62 | Vue.use(VueRouter)
63 |
64 | function load (component) {
65 | // '@' is aliased to src/components
66 | return () => import(`@/${component}.vue`)
67 | }
68 |
69 | const routes = [
70 | {
71 | path: '/',
72 | component: load('Layout'),
73 | meta: { requiresAuth: true, roles: ['user'] },
74 | children: [
75 | { path: '', name: 'home', component: load('Home'), meta: { requiresAuth: true, roles: ['user'] } }
76 | ]
77 | },
78 | { path: '*', component: load('Error404') }, // Not found
79 | { path: '/unauthorized', name: 'Unauthorized', component: load('Unauthorized') } // Unauthorized
80 | ]
81 |
82 | const router = new VueRouter({
83 | /*
84 | * NOTE! VueRouter "history" mode DOESN'T works for Cordova builds,
85 | * it is only to be used only for websites.
86 | *
87 | * If you decide to go with "history" mode, please also open /config/index.js
88 | * and set "build.publicPath" to something other than an empty string.
89 | * Example: '/' instead of current ''
90 | *
91 | * If switching back to default "hash" mode, don't forget to set the
92 | * build publicPath back to '' so Cordova builds work again.
93 | */
94 | mode: 'history',
95 | scrollBehavior: () => ({ y: 0 }),
96 | routes
97 | })
98 |
99 | router.beforeEach((to, from, next) => {
100 | if (to.meta.requiresAuth) {
101 | const auth = store.state.security.auth
102 | if (!auth.authenticated) {
103 | security.init(next, to.meta.roles)
104 | }
105 | else {
106 | if (to.meta.roles) {
107 | if (security.roles(to.meta.roles[0])) {
108 | next()
109 | }
110 | else {
111 | next({ name: 'unauthorized' })
112 | }
113 | }
114 | else {
115 | next()
116 | }
117 | }
118 | }
119 | else {
120 | next()
121 | }
122 | })
123 |
124 | export default router
125 | ```
126 |
127 | Contributions
128 | -----------------------------------------------------------
129 | Any comments or suggestions are very welcome.
130 |
131 | ## License
132 |
133 | [MIT](http://opensource.org/licenses/MIT)
134 |
135 | Copyright (c) 2018-present, Rockt
136 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 |
4 | import security from './modules/security'
5 |
6 | Vue.use(Vuex)
7 |
8 | export default new Vuex.Store({
9 | modules: {
10 | security
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/modules/security/actions.js:
--------------------------------------------------------------------------------
1 | import * as types from './types'
2 |
3 | import store from '../../'
4 |
5 | export default {
6 | authLogin ({ commit }, keycloakAuth) {
7 | store.commit(types.SECURITY_AUTH, keycloakAuth)
8 | },
9 | authLogout ({ commit }) {
10 | commit(types.SECURITY_AUTH)
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/modules/security/getters.js:
--------------------------------------------------------------------------------
1 | import * as types from './types'
2 |
3 | export default {
4 | [types.SECURITY_AUTH]: state => {
5 | return state.auth
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/modules/security/index.js:
--------------------------------------------------------------------------------
1 | import actions from './actions'
2 | import getters from './getters'
3 | import mutations from './mutations'
4 |
5 | const state = {
6 | auth: {
7 | authenticated: false
8 | }
9 | }
10 |
11 | export default {
12 | state,
13 | actions,
14 | getters,
15 | mutations
16 | }
17 |
--------------------------------------------------------------------------------
/modules/security/mutations.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 |
3 | import * as types from './types'
4 |
5 | export default {
6 | [types.SECURITY_AUTH] (state, keycloakAuth) {
7 | state.auth = keycloakAuth
8 | axios.defaults.headers.common = { 'Authorization': 'Bearer ' + keycloakAuth.token }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/modules/security/types.js:
--------------------------------------------------------------------------------
1 | export const SECURITY_AUTH = 'SECURITY_AUTH'
2 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "rockt-vuejs-keycloak",
3 | "version": "0.0.1",
4 | "description": "Vue.js with Keycloak authentication",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [
10 | "security",
11 | "keycloak",
12 | "vuejs"
13 | ],
14 | "author": "Henrique Sakata ",
15 | "contributors": [
16 | { "name": "Silas Silva", "email": "silas.silva@rockt.com.br" }
17 | ],
18 | "license": "Apache-2.0"
19 | }
20 |
--------------------------------------------------------------------------------
/security/header.js:
--------------------------------------------------------------------------------
1 | import store from '../'
2 |
3 | export default () => {
4 | var keycloakAuth = store.getters.SECURITY_AUTH
5 | return { 'Authorization': 'Bearer ' + keycloakAuth.token }
6 | }
7 |
--------------------------------------------------------------------------------
/security/index.js:
--------------------------------------------------------------------------------
1 | import init from './init'
2 | import roles from './roles'
3 | import logout from './logout'
4 | import header from './header'
5 |
6 | export default {
7 | init,
8 | roles,
9 | logout,
10 | header
11 | }
12 |
--------------------------------------------------------------------------------
/security/init.js:
--------------------------------------------------------------------------------
1 | import Keycloak from 'keycloak-js'
2 | import store from '../'
3 |
4 | let keycloakAuth = new Keycloak('/statics/keycloak.json')
5 |
6 | export default (next, roles) => {
7 | keycloakAuth.init({ onLoad: 'login-required' })
8 | .success((authenticated) => {
9 | if (!authenticated) {
10 | window.location.reload()
11 | }
12 | store.dispatch('authLogin', keycloakAuth)
13 | if (roles) {
14 | if (keycloakAuth.hasResourceRole(roles[0])) {
15 | next()
16 | }
17 | else {
18 | next({ name: 'Unauthorized' })
19 | }
20 | }
21 | else {
22 | next()
23 | }
24 | setInterval(function () {
25 | keycloakAuth.updateToken(70)
26 | .success((refreshed) => {
27 | if (refreshed) {
28 | store.dispatch('authLogin', keycloakAuth)
29 | }
30 | else {
31 | console.log('Token not refreshed, valid for ' + Math.round(keycloakAuth.tokenParsed.exp + keycloakAuth.timeSkew - new Date().getTime() / 1000) + ' seconds')
32 | }
33 | }).error(function () {
34 | console.error('Failed to refresh token')
35 | })
36 | }, 60000)
37 | })
38 | .error(() => {
39 | console.log('failed to login')
40 | })
41 | }
42 |
--------------------------------------------------------------------------------
/security/logout.js:
--------------------------------------------------------------------------------
1 | import store from '../'
2 |
3 | export default () => {
4 | var keycloakAuth = store.getters.SECURITY_AUTH
5 | keycloakAuth.logout()
6 | store.dispatch('authLogout')
7 | }
8 |
--------------------------------------------------------------------------------
/security/roles.js:
--------------------------------------------------------------------------------
1 | import store from '../'
2 |
3 | export default (role) => {
4 | var keycloakAuth = store.getters.SECURITY_AUTH
5 | if (keycloakAuth.authenticated) {
6 | return keycloakAuth.hasResourceRole(role)
7 | }
8 | else {
9 | return false
10 | }
11 | }
12 |
--------------------------------------------------------------------------------