├── .babelrc ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── LICENSE ├── README.md ├── build ├── utils.js ├── webpack.config.base.js ├── webpack.config.dev.js └── webpack.config.prod.js ├── index.html ├── package-lock.json ├── package.json ├── src ├── App.vue ├── index.js ├── pages │ ├── AccessDenied.vue │ ├── FreeUser.vue │ ├── Home.vue │ └── PayingUser.vue ├── router │ └── index.js └── services │ ├── ApiService.js │ └── SecurityService.js ├── static ├── callback.html ├── img │ └── logo.png ├── oidc-client.js ├── oidc-client.min.js └── silent-renew.html └── test └── setup.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["@babel/preset-env", { 4 | "modules": "commonjs", 5 | "targets": { 6 | "browsers": ["> 1%", "last 2 versions", "not ie <= 8"], 7 | "node": "current" 8 | } 9 | }] 10 | ] 11 | } -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /config/ 3 | /dist/ -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parserOptions: { 4 | parser: 'babel-eslint' 5 | }, 6 | env: { 7 | browser: true, 8 | node: true, 9 | mocha: true 10 | }, 11 | "globals": { 12 | "expect": true 13 | }, 14 | extends: [ 15 | 'plugin:vue/recommended', 16 | 'standard' 17 | ], 18 | plugins: [ 19 | 'vue' 20 | ], 21 | rules: { 22 | 'generator-star-spacing': 'off', 23 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off' 24 | } 25 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # jest test coverage 21 | .jest_coverage 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # built files 61 | dist -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 João José Paiva Bento Filho 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vuejsoidcclient 2 | 3 | Project vueJs with oidc-client library 4 | 5 | ## Create the development environment 6 | 7 | Npm: 8 | https://nodejs.org/en/download/ 9 | 10 | Npm Version Control on Windows: 11 | https://github.com/felixrieseberg/npm-windows-upgrade 12 | 13 | Npm Version Control on Linux: 14 | https://github.com/creationix/nvm 15 | 16 | ## Technology Version 17 | 18 | Version of npm used in the project: *6.5.0* 19 | Version of oidc-client: *1.6.1* 20 | 21 | ## Identity Provider 22 | 23 | The configuration for the examples are based on running IdentityServer4 on localhost. A ready-to-go reference implementation for testing purposes can be found at [IdentityServer4AndApi][1]. 24 | 25 | ## Documentation 26 | 27 | Oidc-Client: 28 | https://github.com/IdentityModel/oidc-client-js/wiki 29 | 30 | 31 | ## Build Setup 32 | 33 | ``` bash 34 | # install dependencies 35 | npm install 36 | 37 | # serve with hot reload at localhost:8080 38 | npm run dev 39 | 40 | # build for production with minification 41 | npm run prod 42 | ``` 43 | 44 | ## Connection with identity provider 45 | 46 | Change the parameters of the variable **mgr** of the script [SecurityService.js][2] to the values of your identity provider. 47 | ``` bash 48 | var mgr = new Oidc.UserManager({ 49 | userStore: new Oidc.WebStorageStateStore(), 50 | authority: 'https://localhost:44321', 51 | client_id: 'vuejsclient', 52 | redirect_uri: window.location.origin + '/static/callback.html', 53 | response_type: 'id_token token', 54 | scope: 'openid profile address roles identityserver4api country subscriptionlevel offline_access', 55 | post_logout_redirect_uri: window.location.origin + '/index.html', 56 | silent_redirect_uri: window.location.origin + '/static/silent-renew.html', 57 | accessTokenExpiringNotificationTime: 10, 58 | automaticSilentRenew: true, 59 | filterProtocolClaims: true, 60 | loadUserInfo: true 61 | }) 62 | ``` 63 | 64 | The script [SecurityService.js][2] contains triggers and methods from the [oidc-client][3] library. 65 | 66 | ## API 67 | 68 | The script [ApiService.js][4] is responsible for making requests to an API using the libraries [oidc-client][3] and [axios][5] 69 | 70 | The **baseUrl** constant receives the static part of the API Url. 71 | ``` bash 72 | const baseUrl = 'https://localhost:44390/api/'; 73 | ``` 74 | 75 | The **defineHeaderAxios()** method appends the access teken to the axios head. 76 | ``` bash 77 | async defineHeaderAxios () { 78 | await user.getAcessToken().then( 79 | acessToken => { 80 | axios.defaults.headers.common['Authorization'] = 'Bearer ' + acessToken 81 | }, err => { 82 | console.log(err) 83 | }) 84 | } 85 | ``` 86 | 87 | The **getAll()** method makes a get request. It receives as a parameter a string that will be concatenated with the **baseUrl** constant by forming the API Url. 88 | ``` bash 89 | async getAll(api){ 90 | await this.defineHeaderAxios() 91 | return axios 92 | .get(baseUrl + api) 93 | .then(response => response.data) 94 | .catch(err => { 95 | console.log(err); 96 | }) 97 | } 98 | ``` 99 | 100 | ## Route protection 101 | 102 | The script [index.js][7] is responsible for managing the application routes using the [vue router][6]. Each route has a field called **meta**. **Meta** receives two parameters: **requiresAuth** and **role**. 103 | 104 | - **requiresAuth**[Bollean]: Responsible for protecting the route 105 | - **role**[String]: Users with this role will be allowed to access the route 106 | 107 | ``` bash 108 | { 109 | path: '/payinguser', 110 | name: 'PayingUser', 111 | component: PayingUser, 112 | meta: { 113 | requiresAuth: true, 114 | role: ['PayingUser'] 115 | } 116 | }, 117 | { 118 | path: '/freeuser', 119 | name: 'FreeUser', 120 | component: FreeUser, 121 | meta: { 122 | requiresAuth: true, 123 | role: ['FreeUser'] 124 | } 125 | } 126 | ``` 127 | 128 | At each transition of routes in the application, the **router.beforeEach()** method of the script [index.js][8] is called. This method checks whether the user who is logged in is allowed to access the route. It does this by comparing the role of the user and the role of the route. 129 | ``` bash 130 | router.beforeEach((to, from, next) => { 131 | const requiresAuth = to.matched.some(record => record.meta.requiresAuth); 132 | if (requiresAuth) { 133 | mgr.getRole().then( 134 | sucess => { 135 | if (to.meta.role == sucess){ 136 | next(); 137 | }else { 138 | next('/accessdenied'); 139 | } 140 | }, 141 | err => { 142 | console.log(err); 143 | } 144 | ); 145 | } else { 146 | next(); 147 | } 148 | }); 149 | ``` 150 | 151 | [1]: https://github.com/joaojosefilho/IdentityServer4AndApi 152 | [2]: https://github.com/joaojosefilho/vuejsOidcClient/blob/master/src/services/SecurityService.js 153 | [3]: https://github.com/IdentityModel/oidc-client-js/wiki 154 | [4]: https://github.com/joaojosefilho/vuejsOidcClient/blob/master/src/services/ApiService.js 155 | [5]: https://github.com/axios/axios 156 | [6]: https://router.vuejs.org 157 | [7]: https://github.com/joaojosefilho/vuejsOidcClient/blob/master/src/router/index.js 158 | [8]: https://github.com/joaojosefilho/vuejsOidcClient/blob/master/src/index.js 159 | -------------------------------------------------------------------------------- /build/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const path = require('path') 4 | 5 | module.exports = { 6 | resolve: function (dir) { 7 | return path.join(__dirname, '..', dir) 8 | }, 9 | 10 | assetsPath: function (_path) { 11 | const assetsSubDirectory = 'static' 12 | return path.posix.join(assetsSubDirectory, _path) 13 | } 14 | } -------------------------------------------------------------------------------- /build/webpack.config.base.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const HtmlWebpackPlugin = require('html-webpack-plugin') 4 | const CopyWebpackPlugin = require('copy-webpack-plugin') 5 | const { VueLoaderPlugin } = require('vue-loader') 6 | 7 | const utils = require('./utils') 8 | 9 | module.exports = { 10 | resolve: { 11 | extensions: ['.js', '.vue', '.json'], 12 | alias: { 13 | 'assets': utils.resolve('assets'), 14 | 'pages': utils.resolve('src/pages'), 15 | 'static': utils.resolve('static'), 16 | 'components': utils.resolve('src/components'), 17 | 'router': utils.resolve('src/router'), 18 | 'services': utils.resolve('src/services') 19 | } 20 | }, 21 | entry: [ 22 | './src/index.js' 23 | ], 24 | module: { 25 | rules: [ 26 | { 27 | test: /\.(js|vue)$/, 28 | use: 'eslint-loader', 29 | enforce: 'pre' 30 | }, { 31 | test: /\.vue$/, 32 | use: 'vue-loader' 33 | }, { 34 | test: /\.js$/, 35 | use: { 36 | loader: 'babel-loader', 37 | } 38 | }, { 39 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 40 | use: { 41 | loader: 'url-loader', 42 | options: { 43 | limit: 10000, 44 | name: utils.assetsPath('img/[name].[hash:7].[ext]') 45 | } 46 | } 47 | }, { 48 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, 49 | use: { 50 | loader: 'url-loader', 51 | options: { 52 | limit: 10000, 53 | name: utils.assetsPath('media/[name].[hash:7].[ext]') 54 | } 55 | } 56 | }, { 57 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 58 | use: { 59 | loader: 'url-loader', 60 | options: { 61 | limit: 10000, 62 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 63 | } 64 | } 65 | } 66 | ] 67 | }, 68 | 69 | plugins: [ 70 | new HtmlWebpackPlugin({ 71 | filename: 'index.html', 72 | template: 'index.html', 73 | inject: true 74 | }), 75 | new VueLoaderPlugin(), 76 | new CopyWebpackPlugin([ 77 | { 78 | from: utils.resolve('static/img'), 79 | to: utils.resolve('dist/static/img'), 80 | toType: 'dir' 81 | }, 82 | { 83 | from: utils.resolve('static'), 84 | to: utils.resolve('dist/static'), 85 | toType: 'dir' 86 | } 87 | ]) 88 | ] 89 | } -------------------------------------------------------------------------------- /build/webpack.config.dev.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const webpack = require('webpack') 4 | const merge = require('webpack-merge') 5 | const baseConfig = require('./webpack.config.base') 6 | 7 | const HOST = 'localhost' 8 | const PORT = 8080 9 | 10 | module.exports = merge(baseConfig, { 11 | mode: 'development', 12 | 13 | devServer: { 14 | clientLogLevel: 'warning', 15 | hot: true, 16 | contentBase: 'dist', 17 | compress: true, 18 | host: HOST, 19 | port: PORT, 20 | open: true, 21 | overlay: { warnings: false, errors: true }, 22 | publicPath: '/', 23 | quiet: true, 24 | watchOptions: { 25 | poll: true 26 | } 27 | }, 28 | 29 | module: { 30 | rules: [ 31 | { 32 | test: /\.css$/, 33 | use: [ 34 | 'vue-style-loader', 35 | 'css-loader' 36 | ] 37 | }, { 38 | test: /\.styl(us)?$/, 39 | use: [ 40 | 'vue-style-loader', 41 | 'css-loader', 42 | 'stylus-loader' 43 | ] 44 | } 45 | ] 46 | }, 47 | 48 | plugins: [ 49 | new webpack.HotModuleReplacementPlugin() 50 | ] 51 | }) -------------------------------------------------------------------------------- /build/webpack.config.prod.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const merge = require('webpack-merge') 4 | const baseConfig = require('./webpack.config.base') 5 | const MiniCssExtractPlugin = require('mini-css-extract-plugin') 6 | 7 | module.exports = merge(baseConfig, { 8 | mode: 'production', 9 | optimization: { 10 | splitChunks: { 11 | cacheGroups: { 12 | commons: { 13 | test: /[\\/]node_modules[\\/]/, 14 | name: "vendor", 15 | chunks: "all", 16 | }, 17 | }, 18 | }, 19 | }, 20 | module: { 21 | rules: [ 22 | { 23 | test: /\.css?$/, 24 | use: [ 25 | MiniCssExtractPlugin.loader, 26 | 'css-loader' 27 | ] 28 | }, { 29 | test: /\.styl(us)?$/, 30 | use: [ 31 | MiniCssExtractPlugin.loader, 32 | 'css-loader', 33 | 'stylus-loader' 34 | ] 35 | } 36 | ] 37 | }, 38 | plugins: [ 39 | new MiniCssExtractPlugin({ 40 | filename: 'main.css' 41 | }) 42 | ] 43 | }) -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | vuejsclient 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vuejsoidcclient", 3 | "version": "1.0.0", 4 | "description": "project vueJs with oidc-client library", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "webpack-dev-server --progress --config build/webpack.config.dev.js", 8 | "prod": "webpack --config build/webpack.config.prod.js", 9 | "lint": "eslint --ext .js,.vue src", 10 | "lint:fix": "eslint --ext .js,.vue src --fix", 11 | "test": "jest" 12 | }, 13 | "author": "joaojosefilho ", 14 | "license": "MIT", 15 | "dependencies": { 16 | "@babel/polyfill": "^7.2.5", 17 | "axios": "^0.18.0", 18 | "babel-polyfill": "^6.26.0", 19 | "bootstrap": "^4.2.1", 20 | "jquery": "^3.3.1", 21 | "oidc-client": "^1.6.1", 22 | "popper.js": "^1.14.6", 23 | "vue": "^2.5.22", 24 | "vue-router": "^3.0.2" 25 | }, 26 | "devDependencies": { 27 | "@babel/core": "^7.2.2", 28 | "@babel/preset-env": "^7.2.3", 29 | "@vue/test-utils": "^1.0.0-beta.28", 30 | "babel-core": "^7.0.0-bridge.0", 31 | "babel-eslint": "^10.0.1", 32 | "babel-jest": "^23.6.0", 33 | "babel-loader": "^8.0.5", 34 | "copy-webpack-plugin": "^4.6.0", 35 | "css-loader": "^1.0.1", 36 | "eslint": "^5.12.0", 37 | "eslint-config-standard": "^12.0.0", 38 | "eslint-loader": "^2.1.1", 39 | "eslint-plugin-import": "^2.14.0", 40 | "eslint-plugin-node": "^8.0.1", 41 | "eslint-plugin-promise": "^4.0.1", 42 | "eslint-plugin-standard": "^4.0.0", 43 | "eslint-plugin-vue": "^4.7.1", 44 | "html-webpack-plugin": "^3.2.0", 45 | "jest": "^23.6.0", 46 | "jest-serializer-vue": "^2.0.2", 47 | "mini-css-extract-plugin": "^0.4.5", 48 | "stylus": "^0.54.5", 49 | "stylus-loader": "^3.0.2", 50 | "uglify-es": "^3.3.9", 51 | "url-loader": "^1.1.2", 52 | "vue-jest": "^3.0.2", 53 | "vue-loader": "^15.5.1", 54 | "vue-server-renderer": "^2.5.22", 55 | "vue-style-loader": "^4.1.2", 56 | "vue-template-compiler": "^2.5.22", 57 | "webpack": "^4.28.4", 58 | "webpack-cli": "^3.2.1", 59 | "webpack-dev-server": "^3.1.14", 60 | "webpack-merge": "^4.2.1" 61 | }, 62 | "jest": { 63 | "collectCoverage": true, 64 | "collectCoverageFrom": [ 65 | "src/**/*.{js,vue}" 66 | ], 67 | "coverageDirectory": ".jest_coverage", 68 | "moduleFileExtensions": [ 69 | "js", 70 | "vue" 71 | ], 72 | "moduleNameMapper": { 73 | "^@/(.*)$": "/src/$1" 74 | }, 75 | "transform": { 76 | "^.+\\.js$": "babel-jest", 77 | "^.+\\.vue$": "vue-jest" 78 | }, 79 | "snapshotSerializers": [ 80 | "/node_modules/jest-serializer-vue" 81 | ] 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 34 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import Vue from 'vue' 3 | import VueRouter from 'vue-router'; 4 | import router from './router' 5 | import App from './App' 6 | import 'bootstrap' 7 | import 'bootstrap/dist/css/bootstrap.min.css' 8 | import Mgr from './services/SecurityService'; 9 | 10 | Vue.use(VueRouter); 11 | let mgr = new Mgr(); 12 | 13 | new Vue({ 14 | el: '#app', 15 | router, 16 | render: h => h(App) 17 | }) 18 | 19 | router.beforeEach((to, from, next) => { 20 | const requiresAuth = to.matched.some(record => record.meta.requiresAuth); 21 | if (requiresAuth) { 22 | mgr.getRole().then( 23 | sucess => { 24 | if (to.meta.role == sucess){ 25 | next(); 26 | }else { 27 | next('/accessdenied'); 28 | } 29 | }, 30 | err => { 31 | console.log(err); 32 | } 33 | ); 34 | } else { 35 | next(); 36 | } 37 | }); 38 | -------------------------------------------------------------------------------- /src/pages/AccessDenied.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 33 | -------------------------------------------------------------------------------- /src/pages/FreeUser.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 34 | -------------------------------------------------------------------------------- /src/pages/Home.vue: -------------------------------------------------------------------------------- 1 | 110 | 111 | 227 | 228 | 229 | 334 | -------------------------------------------------------------------------------- /src/pages/PayingUser.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 35 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import Home from '../pages/Home' 4 | import PayingUser from '../pages/PayingUser' 5 | import FreeUser from '../pages/FreeUser' 6 | import AccessDenied from '../pages/AccessDenied' 7 | 8 | Vue.use(Router) 9 | 10 | export default new Router({ 11 | routes: [ 12 | { 13 | path: '/', 14 | name: 'Home', 15 | component: Home, 16 | meta: { 17 | requiresAuth: false 18 | } 19 | }, 20 | { 21 | path: '/payinguser', 22 | name: 'PayingUser', 23 | component: PayingUser, 24 | meta: { 25 | requiresAuth: true, 26 | role: ['PayingUser'] 27 | } 28 | }, 29 | { 30 | path: '/freeuser', 31 | name: 'FreeUser', 32 | component: FreeUser, 33 | meta: { 34 | requiresAuth: true, 35 | role: ['FreeUser'] 36 | } 37 | }, 38 | { 39 | path: '/accessdenied', 40 | name: 'AccessDenied', 41 | component: AccessDenied, 42 | meta: { 43 | requiresAuth: false 44 | } 45 | } 46 | ] 47 | }) 48 | -------------------------------------------------------------------------------- /src/services/ApiService.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import axios from 'axios' 3 | import Mgr from './SecurityService' 4 | import 'babel-polyfill'; 5 | 6 | const baseUrl = 'https://localhost:44390/api/'; 7 | var user = new Mgr() 8 | 9 | export default class ApiService { 10 | 11 | async defineHeaderAxios () { 12 | await user.getAcessToken().then( 13 | acessToken => { 14 | axios.defaults.headers.common['Authorization'] = 'Bearer ' + acessToken 15 | }, err => { 16 | console.log(err) 17 | }) 18 | } 19 | 20 | async getAll(api){ 21 | await this.defineHeaderAxios() 22 | return axios 23 | .get(baseUrl + api) 24 | .then(response => response.data) 25 | .catch(err => { 26 | console.log(err); 27 | }) 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /src/services/SecurityService.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import Oidc from 'oidc-client'; 3 | import 'babel-polyfill'; 4 | 5 | var mgr = new Oidc.UserManager({ 6 | userStore: new Oidc.WebStorageStateStore(), 7 | authority: 'https://localhost:44321', 8 | client_id: 'vuejsclient', 9 | redirect_uri: window.location.origin + '/static/callback.html', 10 | response_type: 'id_token token', 11 | scope: 'openid profile address roles identityserver4api country subscriptionlevel offline_access', 12 | post_logout_redirect_uri: window.location.origin + '/index.html', 13 | silent_redirect_uri: window.location.origin + '/static/silent-renew.html', 14 | accessTokenExpiringNotificationTime: 10, 15 | automaticSilentRenew: true, 16 | filterProtocolClaims: true, 17 | loadUserInfo: true 18 | }) 19 | 20 | Oidc.Log.logger = console; 21 | Oidc.Log.level = Oidc.Log.INFO; 22 | 23 | mgr.events.addUserLoaded(function (user) { 24 | console.log('New User Loaded:', arguments); 25 | console.log('Acess_token: ', user.access_token) 26 | }); 27 | 28 | mgr.events.addAccessTokenExpiring(function () { 29 | console.log('AccessToken Expiring:', arguments); 30 | }); 31 | 32 | mgr.events.addAccessTokenExpired(function () { 33 | console.log('AccessToken Expired:', arguments); 34 | alert('Session expired. Going out!'); 35 | mgr.signoutRedirect().then(function (resp) { 36 | console.log('signed out', resp); 37 | }).catch(function (err) { 38 | console.log(err) 39 | }) 40 | }); 41 | 42 | mgr.events.addSilentRenewError(function () { 43 | console.error('Silent Renew Error:', arguments); 44 | }); 45 | 46 | mgr.events.addUserSignedOut(function () { 47 | alert('Going out!'); 48 | console.log('UserSignedOut:', arguments); 49 | mgr.signoutRedirect().then(function (resp) { 50 | console.log('signed out', resp); 51 | }).catch(function (err) { 52 | console.log(err) 53 | }) 54 | }); 55 | 56 | export default class SecurityService { 57 | 58 | // Renew the token manually 59 | renewToken () { 60 | let self = this 61 | return new Promise((resolve, reject) => { 62 | mgr.signinSilent().then(function (user) { 63 | if (user == null) { 64 | self.signIn(null) 65 | } else{ 66 | return resolve(user) 67 | } 68 | }).catch(function (err) { 69 | console.log(err) 70 | return reject(err) 71 | }); 72 | }) 73 | } 74 | 75 | // Get the user who is logged in 76 | getUser () { 77 | let self = this 78 | return new Promise((resolve, reject) => { 79 | mgr.getUser().then(function (user) { 80 | if (user == null) { 81 | self.signIn() 82 | return resolve(null) 83 | } else{ 84 | return resolve(user) 85 | } 86 | }).catch(function (err) { 87 | console.log(err) 88 | return reject(err) 89 | }); 90 | }) 91 | } 92 | 93 | // Check if there is any user logged in 94 | getSignedIn () { 95 | let self = this 96 | return new Promise((resolve, reject) => { 97 | mgr.getUser().then(function (user) { 98 | if (user == null) { 99 | self.signIn() 100 | return resolve(false) 101 | } else{ 102 | return resolve(true) 103 | } 104 | }).catch(function (err) { 105 | console.log(err) 106 | return reject(err) 107 | }); 108 | }) 109 | } 110 | 111 | // Redirect of the current window to the authorization endpoint. 112 | signIn () { 113 | mgr.signinRedirect().catch(function (err) { 114 | console.log(err) 115 | }) 116 | } 117 | 118 | // Redirect of the current window to the end session endpoint 119 | signOut () { 120 | mgr.signoutRedirect().then(function (resp) { 121 | console.log('signed out', resp); 122 | }).catch(function (err) { 123 | console.log(err) 124 | }) 125 | } 126 | 127 | // Get the profile of the user logged in 128 | getProfile () { 129 | let self = this 130 | return new Promise((resolve, reject) => { 131 | mgr.getUser().then(function (user) { 132 | if (user == null) { 133 | self.signIn() 134 | return resolve(null) 135 | } else{ 136 | return resolve(user.profile) 137 | } 138 | }).catch(function (err) { 139 | console.log(err) 140 | return reject(err) 141 | }); 142 | }) 143 | } 144 | 145 | // Get the token id 146 | getIdToken(){ 147 | let self = this 148 | return new Promise((resolve, reject) => { 149 | mgr.getUser().then(function (user) { 150 | if (user == null) { 151 | self.signIn() 152 | return resolve(null) 153 | } else{ 154 | return resolve(user.id_token) 155 | } 156 | }).catch(function (err) { 157 | console.log(err) 158 | return reject(err) 159 | }); 160 | }) 161 | } 162 | 163 | // Get the session state 164 | getSessionState(){ 165 | let self = this 166 | return new Promise((resolve, reject) => { 167 | mgr.getUser().then(function (user) { 168 | if (user == null) { 169 | self.signIn() 170 | return resolve(null) 171 | } else{ 172 | return resolve(user.session_state) 173 | } 174 | }).catch(function (err) { 175 | console.log(err) 176 | return reject(err) 177 | }); 178 | }) 179 | } 180 | 181 | // Get the access token of the logged in user 182 | getAcessToken(){ 183 | let self = this 184 | return new Promise((resolve, reject) => { 185 | mgr.getUser().then(function (user) { 186 | if (user == null) { 187 | self.signIn() 188 | return resolve(null) 189 | } else{ 190 | return resolve(user.access_token) 191 | } 192 | }).catch(function (err) { 193 | console.log(err) 194 | return reject(err) 195 | }); 196 | }) 197 | } 198 | 199 | // Takes the scopes of the logged in user 200 | getScopes(){ 201 | let self = this 202 | return new Promise((resolve, reject) => { 203 | mgr.getUser().then(function (user) { 204 | if (user == null) { 205 | self.signIn() 206 | return resolve(null) 207 | } else{ 208 | return resolve(user.scopes) 209 | } 210 | }).catch(function (err) { 211 | console.log(err) 212 | return reject(err) 213 | }); 214 | }) 215 | } 216 | 217 | // Get the user roles logged in 218 | getRole () { 219 | let self = this 220 | return new Promise((resolve, reject) => { 221 | mgr.getUser().then(function (user) { 222 | if (user == null) { 223 | self.signIn() 224 | return resolve(null) 225 | } else{ 226 | return resolve(user.profile.role) 227 | } 228 | }).catch(function (err) { 229 | console.log(err) 230 | return reject(err) 231 | }); 232 | }) 233 | } 234 | } -------------------------------------------------------------------------------- /static/callback.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Waiting... 7 | 8 | 9 | 10 | 11 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /static/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaojosefilho/vuejsOidcClient/c30d31788ca14521f66c0edb3f89c545880fc287/static/img/logo.png -------------------------------------------------------------------------------- /static/silent-renew.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Silent Renew Token for SpeEDI Cargo 5 | 6 | 7 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /test/setup.js: -------------------------------------------------------------------------------- 1 | // setup JSDOM 2 | require('jsdom-global')() 3 | 4 | // make expect available globally 5 | global.expect = require('expect') 6 | --------------------------------------------------------------------------------