Trying to change a torii authenticator to return an account id from the response, so it's available in the session for fetching the account.
In trying to adapt the example to the torii authenticator, I have this starting point (obviously wrong, hitting on my js knowledge limits):
import Ember from 'ember';
import Torii from 'simple-auth-torii/authenticators/torii';
import Configuration from 'simple-auth-oauth2/configuration';
export default Torii.extend({
authenticate: function(credentials) {
return this._super(provider).then((authResponse) => {
return new Ember.RSVP.Promise(function(resolve, reject) {
Ember.$.ajax({
url: Configuration.serverTokenEndpoint,
type: 'POST',
data: { 'auth_code': authResponse.authorizationCode }
}).then(function(response) {
Ember.run(function() {
// all properties this promise resolves
// with will be available through the session
resolve({ access_token: response.access_token, account_id: response.account_id });
});
}, function(xhr, status, error) {
Ember.run(function() {
reject(xhr.responseText);
});
});
});
});
}
});
Ember doesn't complain with any errors, but of course facebook's auth dialog doesn't pop. Lost at this point, any pointers would be greatly appreciated.
Update
This is the provider code, which was working before changing the authenticator to try and return the account_id as well:
import Ember from 'ember';
import FacebookOauth2 from 'torii/providers/facebook-oauth2';
let { resolve } = Ember.RSVP;
export default FacebookOauth2.extend({
fetch(data) {
return resolve(data);
},
close() {
return resolve();
}
});
This is the previous, working authenticator:
import Ember from 'ember';
import Torii from 'simple-auth-torii/authenticators/torii';
import Configuration from 'simple-auth-oauth2/configuration';
export default Torii.extend({
authenticate(provider) {
return this._super(provider).then((authResponse) => {
return Ember.$.post(Configuration.serverTokenEndpoint, { 'auth_code': authResponse.authorizationCode }).then(function(response) {
return { 'access_token': response['access_token'], provider };
});
});
}
});
Related
I'm new to Vue 3 (cli) and I'm not at all comfortable with front-end technology, so I'm having a hard time understanding the information I'm reading.
I succeeded in creating a registration/login interface with an api and JWT. The user information needs to be persisted everywhere in the project I'm doing to train myself, so I configured axios in my store.
store/index.js
import { createStore } from 'vuex'
import axios from 'axios';
const api = axios.create({
baseURL: 'http://127.0.0.1:7000'
});
let user = localStorage.getItem('user');
if(null === user) {
user = {uuid: '', token: ''};
} else {
try {
user = JSON.parse(user);
api.defaults.headers.common['Authorization'] = 'Bearer ' + user.token;
} catch (e) {
user = {uuid: '', token: ''};
}
}
export default createStore({
state: {
status: '',
user: user,
userInfos: {},
},
mutations: {
[...]
},
getters: {
},
actions: {
[...]
},
modules: {
}
})
I would like to be able to use api from my components. I have had several approaches:
1 - I have imported axios into my component, but this is not correct at all, as I will need axios in all my components.
2 - I've looked at different documentations that explain how to configure axios globally, but no two are the same and I couldn't get anything to work.
3 - I've tried calling api through strangenesses like this.$store.api in my methods, but obviously this is abused.
Can anyone help me understand what is the right way to use axios from my components and from the store with only one configuration? Knowing that I need to be able to keep my headers up to date for authentication with the Bearer Token (a mutation updates it in the store at user login).
main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap/dist/js/bootstrap.js'
import { library } from '#fortawesome/fontawesome-svg-core'
import { FontAwesomeIcon } from '#fortawesome/vue-fontawesome'
import { faMedal } from '#fortawesome/free-solid-svg-icons'
import { faLaptopMedical } from '#fortawesome/free-solid-svg-icons'
import { faCookieBite } from '#fortawesome/free-solid-svg-icons'
import { faCoins } from '#fortawesome/free-solid-svg-icons'
import { faHourglassStart } from '#fortawesome/free-solid-svg-icons'
import { faUpRightFromSquare } from '#fortawesome/free-solid-svg-icons'
import { faInfo } from '#fortawesome/free-solid-svg-icons'
import { faGears } from '#fortawesome/free-solid-svg-icons'
library.add(
faMedal,
faCoins,
faLaptopMedical,
faCookieBite,
faHourglassStart,
faUpRightFromSquare,
faInfo,
faGears
);
createApp(App)
.component('font-awesome-icon', FontAwesomeIcon)
.use(store)
.use(router)
.mount('#app')
Thank you very much for your help.
If you're creating a new app, I would use Pinia, which is really the next version of VueX. Don't put the user in localStorage, but in a store that you can access from all views and components.
So Axios setup in composables/myaxiosfile.js
// src/stores/oneStore.js
import { defineStore } from "pinia";
// Possibly import and deconstruct functions from #/api.js and use
// those functions in the "actions" section of the store,
// updating the state according to the answer of the api call.
export const useOneStore = defineStore("oneStore", {
state: () => {
return {
user: true
}
}
// actions
// getters
})
and in a component :
import { useOneStore } from '../stores/oneStore';
const oneStore = useOneStore()
I don't know if this is the right way, but by doing so, it allows me to use the store api in my components.
store/index.js
state: {
api: {},
[...]
},
mutations: {
setApi: function (state, api) {
state.api = api;
},
connexionUser: function (state, user) {
state.user = user;
api.defaults.headers.common['Authorization'] = 'Bearer ' + user.token;
state.api = api;
},
[...]
},
actions: {
setApi: ({commit}) => {
commit('setApi', api);
},
[...]
},
App.vue
mounted() {
this.$store.dispatch('setApi');
[...]
}
Like this, offline, it loads api which is set at the top of my store (see in my question) and when I log in, I update api in state to have JWT authentication.
So the problem is that I would like to use Axios instance. Because:
new useFetch is only possible to use inside of components aka setup scrips. https://v3.nuxtjs.org/guide/features/data-fetching/
community axios module is only possible inside of nuxt2 https://github.com/nuxt-community/axios-module/issues/536 and are nor supported in nuxt3
I need to make calls in pinia actions(store) to my backend service.
nuxt.config.js
import { defineNuxtConfig } from "nuxt";
export default defineNuxtConfig({
runtimeConfig: {
public: {
apiBase: process.env.API_BASE_URL ?? "http://localhost:8080/api/v1",
},
},
env: {
apiBase: process.env.API_BASE_URL ?? "http://localhost:8080/api/v1",
},
buildModules: ["#pinia/nuxt"],
});
and here is instance.js
import axios, { AxiosResponse } from "axios";
const instance = axios.create({
baseURL: process.env.API_BASE_URL,
});
instance.interceptors.response.use((response: AxiosResponse) => {
return response.data;
});
export default instance;
So it does see the envs on server-side as I can console log them but on client I do receive can't read of undefined
You can access your env variables using a composable and the useRuntimeConfig method.
Something like this for instance:
// file composables/use-axios-instance.ts
import axios, { AxiosResponse } from "axios";
let instance = null;
export const useAxiosInstance = () => {
const { API_BASE_URL } = useRuntimeConfig();
if (!instance) {
instance = axios.create({
baseURL: API_BASE_URL,
});
instance.interceptors.response.use((response: AxiosResponse) => {
return response.data;
});
}
return instance;
};
Then you can access to your axios instance using const axios = useAxiosInstance();
I'm using next-auth with Prisma and Graphql, I followed these instructions to set up the adapter and my models accordingly:
https://next-auth.js.org/adapters/prisma
Authentication works but when I inspect session object from here :
const { data: session, status } = useSession()
I don't see ID
The reason I need the ID is to make further GraphQL queries. I'm using email value for now to fetch the User by email, but having ID available would be a better option.
Here's the quickest solution to your question:
src/pages/api/auth/[...nextAuth].js
export default NextAuth({
...
callbacks: {
session: async ({ session, token }) => {
if (session?.user) {
session.user.id = token.uid;
}
return session;
},
jwt: async ({ user, token }) => {
if (user) {
token.uid = user.id;
}
return token;
},
},
session: {
strategy: 'jwt',
},
...
});
This worked for me.
callbacks: {
async jwt({token, user, account, profile, isNewUser}) {
user && (token.user = user)
return token
},
async session({session, token, user}) {
session = {
...session,
user: {
id: user.id,
...session.user
}
}
return session
}
}
Here's the quickest solution that worked for me
import NextAuth from "next-auth"
import { MongoDBAdapter } from "#next-auth/mongodb-adapter"
import clientPromise from "../../../lib/mongodb"
export const authOptions = {
providers: [
<...yourproviders>
],
callbacks: {
session: async ({ session, token, user }) => {
if (session?.user) {
session.user.id = user.id;
}
return session;
},
},
adapter: MongoDBAdapter(clientPromise),
}
I just referred to the NextAuth docs (this page) and finally got it working the right way
callbacks: {
jwt({ token, account, user }) {
if (account) {
token.accessToken = account.access_token
token.id = user?.id
}
return token
}
session({ session, token }) {
// I skipped the line below coz it gave me a TypeError
// session.accessToken = token.accessToken;
session.user.id = token.id;
return session;
},
}
If you use TypeScript, add this to a new file called next-auth.d.ts
import NextAuth from 'next-auth';
declare module 'next-auth' {
interface Session {
user: {
id: string;
} & DefaultSession['user'];
}
}
I believe you can change the callbacks so it includes the user's ID in the session: https://next-auth.js.org/configuration/callbacks.
You will need to change the JWT callback so it also include the userId and the session callback so the id is also persisted to the browser session.
I have the following vue file. My REST API base URL is http://localhost:8080/api/. When I access http://localhost:8080/api/dfc/system/docbases directly, I get the response as shown.
["gr_swy","SubWayX_DEMO"]
But I want to get the response through nuxt js which is running on http://localhost:3000/restapi/. I tried to follow all the articles, but not able to figure out where I'm doing wrong.
<template>
<div class="container">
{{docbases}}
</div>
</template>
<script>
import axios from "axios";
#import axios from "../../.nuxt/axios"; (tried both)
export default {
methods: {
// asyncData({ req, params }) {
// return axios.get("http://localhost:8080/api/dfc/system/docbases")
// .then(res => {
// return { docbases: res.data };
// }).catch((e) => {
// error({ statusCode: 404, message: 'Not found' })
// })
// },
async asyncData ({ params }) {
const { data } = await axios.get('http://localhost:8080/api/dfc/system/docbases');
return { docbases: data }
}
},
head: {
title: "D2Rest"
}
};
</script>
My nuxt.config.js is like this: I tried changeOrigin with true and false both. Can you please help me what extra things I need to configure?
axios: {
proxy: true,
},
env: {
baseUrl: process.env.BASE_URL || 'http://localhost:3000'
},
proxy: {
'/api/': {
target: 'http://localhost:8080/',
pathRewrite: { "^/api": "" },
changeOrigin: false,
prependPath: false
}
},
Based on your configuration, I'm assuming you're using the Nuxt Axios module...
The problem seems to be that you're importing Axios unnecessarily, thus bypassing your axios configuration in nuxt.config.js. The Nuxt Axios module docs describe its usage in components:
export default {
async asyncData({ $axios }) {
const ip = await $axios.$get('http://icanhazip.com')
return { ip }
}
}
Note the destructured parameter $axios. Use that parameter instead of importing your own instance of axios (i.e., don't do import axios from 'axios'), which is not the same as the one configured by Nuxt. No other imports are needed for $axios.
Proxy URL
Another problem is that your explicitly requesting the proxy address in the URL, but that should be excluded:
// const { data } = await $axios.get('http://localhost:8080/api/dfc/system/docbases'); // DON'T DO THIS
const { data } = await $axios.get('/api/dfc/system/docbases');
Sorry, I didn't enable Cross Origin in my java code. I have enabled now and it's resolved.
#CrossOrigin(origins = "http://localhost:3000")
Has anyone used the component named ng2-facebook-sdk? If so does anyone know how I would go about fetching user data from the graph api using the .api method.
Here's the link to the npm package readme guide.I could not understand how to use it - https://www.npmjs.com/package/ng2-facebook-sdk.
My problem is that i have successfully logged in the user but i am not able to write the .api function which returns a Promise object
Currently my code looks like this...
import { Component } from "#angular/core";
import {FacebookService, FacebookInitParams} from "ng2-facebook-sdk";
import { Http } from "#angular/http";
import * as http from "selenium-webdriver/http";
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
name = "";
isUser = false;
no = false;
constructor(private _facebookService: FacebookService,private http:Http) {
let fbParams: FacebookInitParams = {
appId: 'xxxxxxxxxxxxxxx',
xfbml: true,
version: 'v2.6'
};
this._facebookService.init(fbParams);
}
login() {
this._facebookService.login().then((response) => {
this.getUserData();
console.log(response);
});
}
getUserData(){
this._facebookService.api('/me', http,(res) {
this.name = res.name;
this.isUser = true;
});
}
}
I figured it out myself. I was not handling the Promise object response correctly.
This should have been the login function ->
login() {
this._facebookService.login().then((response) => {
var promise = this._facebookService.api('/me');
promise.then((res)=> {
this.id = res.id;
this.name = res.name;
this.isUser = true ;
console.log(res);
});
console.log(response);
});
}