diff --git a/fda-ui/api/user/index.js b/fda-ui/api/user/index.js index ce0317ad3d4566da88394bd2c134f662631f16cf..f4bb4590c1c55fff843af8381f484ff624265a35 100644 --- a/fda-ui/api/user/index.js +++ b/fda-ui/api/user/index.js @@ -1,7 +1,9 @@ +// eslint-disable-next-line camelcase +import jwt_decode from 'jwt-decode' const axios = require('axios/dist/browser/axios.cjs') const qs = require('qs') -const { clientSecret } = require('@/config') -function authenticate (username, password) { + +export function authenticate (clientSecret, username, password) { const payload = { client_id: 'dbrepo-client', username, @@ -10,12 +12,44 @@ function authenticate (username, password) { client_secret: clientSecret, scope: 'openid' } - console.debug('===>', clientSecret) return axios.post('/api/auth/realms/dbrepo/protocol/openid-connect/token', qs.stringify(payload), { headers: { ContentType: 'application/form-data' } }) } -module.exports = { - authenticate +export function userinfo (clientSecret, token) { + return axios.get('/api/auth/realms/dbrepo/protocol/openid-connect/userinfo', { + headers: { + Authorization: `Bearer ${token}`, + ContentType: 'application/form-data' + } + }) +} + +export function refresh (clientSecret, token) { + const payload = { + client_id: 'dbrepo-client', + grant_type: 'refresh_token', + client_secret: clientSecret, + refresh_token: token + } + return axios.post('/api/auth/realms/dbrepo/protocol/openid-connect/token', qs.stringify(payload), { + headers: { ContentType: 'application/form-data' } + }) +} + +export function tokenToUser (token) { + const data = jwt_decode(token) + return { + id: data.sub, + firstname: data.given_name, + lastname: data.family_name, + username: data.preferred_username, + theme_dark: data.theme_dark, + titles_before: data.titles_before, + titles_after: data.titles_after, + affiliation: data.affiliation, + orcid: data.orcid, + email_verified: data.email_verified + } } diff --git a/fda-ui/layouts/default.vue b/fda-ui/layouts/default.vue index 3b310b25aba3d80ca452a9f31c8a3cb94b4a8321..35ccd85ca99ad7e19d6f3ee7eb75127aa3b9360e 100644 --- a/fda-ui/layouts/default.vue +++ b/fda-ui/layouts/default.vue @@ -122,7 +122,8 @@ </template> <script> -import { isDeveloper, jwtToUser } from '@/utils' +import { isDeveloper } from '@/utils' +import { tokenToUser } from '@/api/user' export default { name: 'DefaultLayout', data () { @@ -136,13 +137,7 @@ export default { loadingUser: true, loadingSearch: false, loadingDatabases: false, - search: null, - refreshToken: { - client_id: 'dbrepo-client', - grant_type: 'refresh_token', - client_secret: this.$config.client_secret, - refresh_token: null - } + search: null } }, computed: { @@ -179,13 +174,8 @@ export default { headers: { Authorization: `Bearer ${this.token}` } } }, - keycloakConfig () { - return { - headers: { - Authorization: `Bearer ${this.token}`, - ContentType: 'application/x-www-form-urlencoded' - } - } + clientSecret () { + return this.$config.clientSecret }, silentConfig () { return { @@ -252,21 +242,19 @@ export default { }, logout () { this.$store.commit('SET_TOKEN', null) - this.$store.commit('SET_REFRESH_TOKEN', null) this.$store.commit('SET_USER', null) this.$store.commit('SET_ACCESS', null) this.$vuetify.theme.dark = false this.$router.push('/container') }, - async loadUser () { + loadUser () { if (!this.token) { return } try { this.loadingUser = true - const res = await this.$axios.get('/api/auth/realms/dbrepo/protocol/openid-connect/userinfo', this.keycloakConfig) - const user = jwtToUser(res.data) - console.debug('user information', user) + const user = tokenToUser(this.token) + console.debug('user', user) this.$store.commit('SET_USER', user) this.$vuetify.theme.dark = user.theme_dark this.loading = false diff --git a/fda-ui/nuxt.config.js b/fda-ui/nuxt.config.js index d5ca9c8cae59bc2d3bba419cff396660b21da296..840e02341c795c2e4969bea69c85c66c65d945f9 100644 --- a/fda-ui/nuxt.config.js +++ b/fda-ui/nuxt.config.js @@ -2,9 +2,6 @@ import path from 'path' import colors from 'vuetify/es5/util/colors' import { sandbox, title, icon, brokerUsername, brokerPassword, sharedFilesystem, version, logo, mailVerify, tokenMax, elasticPassword, clientSecret, api, search } from './config' -// pick env vars from .env file or get them passed through docker-compose -require('dotenv').config() - if (sandbox) { console.info('[FDA] Running in sandbox environment') } diff --git a/fda-ui/package.json b/fda-ui/package.json index e80cb0ce28d45fa035bf1e7fd21b771b2fb2851a..ff23e62ae94a9fff5f6ad2d24cc4092fa5e861d5 100644 --- a/fda-ui/package.json +++ b/fda-ui/package.json @@ -36,6 +36,7 @@ "express": "^4.17.1", "is-docker": "^2.2.1", "jose": "^4.9.2", + "jwt-decode": "^3.1.2", "knex": "^0.95.6", "lodash": "^4.17.21", "moment": "^2.29.1", diff --git a/fda-ui/pages/login.vue b/fda-ui/pages/login.vue index 434c091a86c2bd71d5fe1364a7f609f440dfdbb4..93af6d744a4d6f66dbc9c6fc813adf6aa4852d42 100644 --- a/fda-ui/pages/login.vue +++ b/fda-ui/pages/login.vue @@ -56,14 +56,14 @@ </template> <script> -import { authenticate } from '@/api/user' +import { authenticate, tokenToUser } from '@/api/user' export default { data () { return { loading: false, error: false, // XXX: `error` is never changed valid: false, - username: null, + username: 'mweise', password: null } }, @@ -77,6 +77,9 @@ export default { user () { return this.$store.state.user }, + clientSecret () { + return this.$config.clientSecret + }, config () { if (this.token === null) { return {} @@ -102,38 +105,28 @@ export default { async login () { try { this.loading = true - const res = await authenticate(this.username, this.password) + const res = await authenticate(this.clientSecret, this.username, this.password) console.debug('login user', res.data) - // eslint-disable-next-line camelcase - // const { access_token, refresh_token } = res.data - // this.$store.commit('SET_TOKEN', access_token) - // this.$store.commit('SET_REFRESH_TOKEN', refresh_token) - // const data = VueJwtDecode.decode(access_token) - // const user = { - // id: data.sub, - // firstname: data.given_name, - // lastname: data.family_name, - // username: data.preferred_username, - // theme_dark: data.theme_dark, - // email_verified: data.email_verified - // } - // this.$store.commit('SET_USER', user) - // this.$vuetify.theme.dark = user?.theme_dark || false - // await this.$router.push({ path: this.$route.query.redirect ? this.$route.query.redirect : '/container' }) + this.$store.commit('SET_TOKEN', res.data.access_token) + const user = tokenToUser(this.token) + console.debug('user', user) + this.$store.commit('SET_USER', user) + this.$vuetify.theme.dark = user?.theme_dark || false + await this.$router.push({ path: this.$route.query.redirect ? this.$route.query.redirect : '/container' }) } catch (error) { console.error('Failed to login', error) - // const { status } = error.response - // if (status === 418) { - // this.$toast.error('Check your inbox and confirm your e-mail address') - // console.error('user has not confirmed e-mail', error) - // } else if (status === 404) { - // this.$toast.error('Username not found') - // console.error('user has not confirmed e-mail', error) - // } else { - // this.$toast.error('Login not successful') - // console.error('login user failed', error) - // } - // this.loading = false + const { status } = error.response + if (status === 418) { + this.$toast.error('Check your inbox and confirm your e-mail address') + console.error('user has not confirmed e-mail', error) + } else if (status === 404) { + this.$toast.error('Username not found') + console.error('user has not confirmed e-mail', error) + } else { + this.$toast.error('Login not successful') + console.error('login user failed', error) + } + this.loading = false } }, signup () { diff --git a/fda-ui/pages/user/info.vue b/fda-ui/pages/user/info.vue index d9d6adc43651dc3c141f8ff182316bd08fef7096..d927c7a516ae9f9fa062180baca539c0aadc8ea0 100644 --- a/fda-ui/pages/user/info.vue +++ b/fda-ui/pages/user/info.vue @@ -1,5 +1,6 @@ <template> <div v-if="token"> + <pre>{{ model }}</pre> <pre>{{ user }}</pre> <UserToolbar /> <v-tabs-items v-model="tab"> @@ -174,15 +175,7 @@ export default { } }, mounted () { - this.model.id = this.user.id - this.model.username = this.user.username - this.model.firstname = this.user.firstname - this.model.lastname = this.user.lastname - this.model.titles_before = this.user.titles_before - this.model.titles_after = this.user.titles_after - this.model.affiliation = this.user.affiliation - this.model.orcid = this.user.orcid - this.model.theme_dark = this.user.theme_dark + this.model = Object.assign({}, this.user) }, methods: { submit () { diff --git a/fda-ui/yarn.lock b/fda-ui/yarn.lock index 3ca5ba3bbdd1ae9baf45f3e80b9d117037d8068c..bff2f60529e64d54be07f685b751033d20e69b24 100644 --- a/fda-ui/yarn.lock +++ b/fda-ui/yarn.lock @@ -5779,11 +5779,6 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fs@^0.0.1-security: - version "0.0.1-security" - resolved "https://registry.yarnpkg.com/fs/-/fs-0.0.1-security.tgz#8a7bd37186b6dddf3813f23858b57ecaaf5e41d4" - integrity sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w== - fsevents@^1.2.7: version "1.2.13" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" @@ -7631,6 +7626,11 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" +jwt-decode@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/jwt-decode/-/jwt-decode-3.1.2.tgz#3fb319f3675a2df0c2895c8f5e9fa4b67b04ed59" + integrity sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A== + keyv@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9"