I am trying to make a site in Vue and backend on Spring. I want to use rsocket to transfer data, but as soon as I add rsocket seurity in spring, I get :
'metadata is malformed'
Would like to take a look at a working example using jwt/simpleauth
I solved the issue with Simple Auth, now I would like to synchronize this authorization with spring websecurity.
Those. so that routing in rsocket checks authorization via websecurity. I know that this can be implemented through the jwt token, i.e. send a jwt token to a client via rest, but how can I do this in code? JS client (browser) and Spring, how do I generate userdetails token?
Just in case, I'll leave an example of the simpleauth implementation:
// METADATA BUILDER
import {encodeRoute, encodeBearerAuthMetadata, encodeSimpleAuthMetadata, encodeAndAddCustomMetadata, encodeAndAddWellKnownMetadata, MESSAGE_RSOCKET_ROUTING, MESSAGE_RSOCKET_AUTHENTICATION} from "rsocket-core";
export default class Metadata {
constructor(json) {
this.route = json['route'];
this.auth = json['auth'];
}
toMetadata() {
let metadata = Buffer.alloc(0);
if (this.auth) {
if (this.auth["type"] === 'bearer') {
metadata = encodeAndAddCustomMetadata(
metadata,
MESSAGE_RSOCKET_AUTHENTICATION.string,
encodeBearerAuthMetadata(this.auth["token"]),
);
}
if (this.auth["type"] === 'simple') {
metadata = encodeAndAddCustomMetadata(
metadata,
MESSAGE_RSOCKET_AUTHENTICATION.string,
encodeSimpleAuthMetadata(this.auth["username"], this.auth["password"]),
);
}
}
if (this.route) {
metadata = encodeAndAddWellKnownMetadata(
metadata,
MESSAGE_RSOCKET_ROUTING,
encodeRoute(this.route)
);
}
return metadata;
}
}
// RSOCKET CLIENT CLASS
import RSocketWebSocketClient from "rsocket-websocket-client";
import {BufferEncoders, MESSAGE_RSOCKET_COMPOSITE_METADATA, RSocketClient,toBuffer} from "rsocket-core";
import Metadata from "./metadata";
export default class SpringClient {
constructor(wsUrl, keepAlive = 60000, lifetime = 180000, dataMimeType = "application/json") {
this.client = new RSocketClient({
"setup": {
"keepAlive": keepAlive,
"lifetime": lifetime,
"dataMimeType": dataMimeType,
"metadataMimeType": MESSAGE_RSOCKET_COMPOSITE_METADATA.string
},
"transport": new RSocketWebSocketClient({
"url": wsUrl
}, BufferEncoders)
});
}
bearerAuth(token) {
this.auth = {type: "bearer", token: token}
}
simpleAuth(username, password) {
this.auth = {type: "simple", username: username, password: password}
}
logout() {
this.auth = null;
}
connect(
completeCallback = (socket) => {
}, errorCallback = (error) => {
}, subscribeCallback = (cancel) => {
}
) {
this.client.connect().subscribe({
onComplete: socket => {
this.socket = socket;
completeCallback(socket);
},
onError: error => {
errorCallback(error);
},
onSubscribe: cancel => {
subscribeCallback(cancel);
}
});
}
requestResponse(data, route,
completeCallback = (data) => {
},
errorCallback = (error) => {
},
subscribeCallback = (cancel) => {
}
) {
if (this.socket) {
const metadata = new Metadata({
route: route,
auth: this.auth
}).toMetadata();
data = toBuffer(data);
this.socket.requestResponse({
data,
metadata
}).subscribe({
onComplete: data => {
completeCallback(data);
},
onError: error => {
errorCallback(error);
},
onSubscribe: cancel => {
subscribeCallback(cancel);
}
});
}
}
}
// EXAMPLE, HOW TO USE
import SpringClient from "./springclient";
this.client = new SpringClient("ws://localhost:7000/", 5000, 15000, "text/plain");
this.client.connect(
(socket) => {
console.log("got connection complete");
this.socket = socket;
},
(error) => {
console.log("got connection error");
console.error(error);
},
(cancel) => {
console.log("got connection subscribe");
/* call cancel() to abort */
}
)
this.client.simpleAuth("LOGIN", "PASSWORD");
this.client.requestResponse("MESSAGE", "ROUTE",
(data) => {
console.log("got response with requestResponse");
console.log(data.data);
},
(error) => {
console.log("got error with requestResponse");
console.error(error);
},
(cancel) => {
console.log(message);
/* call cancel() to stop onComplete/onError */
}
);
Related
import {
createClient,
defaultExchanges,dedupExchange, cacheExchange, fetchExchange,
subscriptionExchange,
gql
} from "#urql/core";
import { createClient as createWSClient } from "graphql-ws";
import { pipe, subscribe } from "wonka";
import { getToken, setToken } from "./helper";
const wsClient = createWSClient({
url: 'wss://**********/subscriptions',
reconnect: true,
});
const client = createClient({
url: "https://***********/",
fetchOptions: () => {
const token = getToken()
return token ? { headers: { authorization: `Bearer "${token}"` } } : {}
},
// the default:
exchanges: [
...defaultExchanges,
subscriptionExchange({
forwardSubscription(operation) {
return {
subscribe: (sink) => {
const dispose = wsClient.subscribe(operation, sink);
return {
unsubscribe: dispose,
};
},
};
},
}),
]
});
SUB_TO_MESSAGES = async () => {
console.log('sub')
const token = getToken();
console.log(String(token))
const { unsubscribe } = pipe(
await client.subscription(messageAdded,{ jwt: token }),
subscribe((result) => {
console.log(result)
})
)
};
I dont get the same issue with try and catch using GraphQL-WS but I still dont get any data from the server. The assignment is a vanillaJS project using GraphQL.I didndt post the url, jwt token,or the GET, POST, REgG as they work as intended. The rendering is done with a proxy. The error message is:
Connection Closed: 4500 Cannot read properties of undefined (reading 'Authorization')
Even playground doesnt work. Something wrong with the endpoint. It worked 2 weeks ago but admin says it still work yet I can find the problem. It used to work for me.
Here is the try and catch version:
import { createClient} from "graphql-ws";
import pStore from "./handler.js";
import { getToken } from "./helper";
const client = createClient({
url: "wss://******/subscriptions",
reconnect: true,
connectionParams:{
headers: {
"Authorization":`Bearer ${getToken()}`
}
},
})
async SUB_MESSAGE() {
try {
console.log('called Gql server')
const onNext = (res) => {
let obj = res.data.messageAdded
console.log(obj)
pStore[obj.id] = obj
pStore.render(obj)
};
let unsubscribe = () => {
/* complete the subscription */
};
new Promise((resolve, reject) => {
client.subscribe({
query: `subscription{messageAdded(jwt:"${getToken()}"){id text fromAgent createdAt updatedAt}}`,
},
{
next: (data)=> onNext(data),
error: reject,
complete: () => resolve(true),
})
})
}catch(error){
console.error('There has been a problem with your ws operation:', error);
}
}
Either way I think its a ad character, scope issue but I dont know where.
I am trying to check if a user is authenticated and redirect them depending on the page they are in. for example if the user is logged in and they try to visit the login or signup page, they should be redirected. I have a middleware for that.
when I log in the user, the authenticateUser action runs and the user is created, when I check my cookies and local storage on the browser, I see that it is set correctly, but when I visit the login page after logging in, it doesn't redirect me.
middleware/altauth.js
export default function (context) {
console.log(context.store.getters('profile/isAuthenticated'))
if (context.store.getters.isAuthenticated) {
context.redirect('/')
}
}
also the token is both saved using Cookies and local storage and is persistence is through this middleware
middleware/checkauth.js
export default function (context) {
if(context.hasOwnProperty('ssrContext')) {
context.store.dispatch('profile/initAuth', context.ssrContext.req);
} else {
context.store.dispatch('profile/initAuth', null);
}
}
and below are the values for my store
import Cookie from 'js-cookie';
export const state = () => ({
token: null,
})
export const mutations = {
setToken(state, token) {
state.token = token
},
clearToken(state) {
state.token = null
}
}
export const actions = {
async authenticateUser(vuexContext, authData) {
let authUrl = 'https://look.herokuapp.com/signup/'
if (authData.isLogin) {
authUrl = 'https://look.herokuapp.com/login/'
}
return this.$axios
.$post(authUrl, authData.form)
.then(data => {
console.log(data);
const token = data.token
vuexContext.commit('setToken', token)
localStorage.setItem("token", token)
Cookie.set('jwt', token);
})
.catch(e => console.log(e))
},
initAuth(vuexContext, req) {
let token
if (req) {
if (!req.headers.cookie) {
return;
}
const jwtCookie = req.headers.cookie
.split(';')
.find(c => c.trim().startsWith('jwt='));
if (!jwtCookie) {
return;
}
token = jwtCookie.split('=')[1];
} else {
token = localStorage.getItem('token');
if (!token) {
return;
}
}
vuexContext.commit('setToken', token);
}
}
export const getters = {
isAuthenticated(state) {
return state.token != null;
},
}
please help, i don't know what the problem can be
Here is a basic but full example for auth system in SSR nuxt
You will need two apis for this, one will return token info with user info, and the other will return user info only.
for example
POST http://example.com/api/auth/authorizations
{
token: 'abcdefghijklmn',
expired_at: 12345678,
user: {
name: 'Tom',
is_admin: true
}
}
// this need authed
GET http://example.com/api/auth/user
{
name: 'Tom',
is_admin: true
}
nuxt.config.js
plugins:[
'~plugins/axios',
],
buildModules: [
'#nuxtjs/axios',
],
router: {
middleware: [
'check-auth'
]
},
./pages/login.vue
<template>
<form #submit.prevent="login">
<input type="text" name="username" v-model="form.username">
<input type="password" name="password" v-model="form.password">
</form>
</template>
<script type="text/javascript">
export default{
data(){
return {
form: {username: '', password: ''}
}
},
methods: {
login(){
this.$axios.post(`/auth/authorizations`, this.form)
.then(({ data }) => {
let { user, token } = data;
this.$store.commit('auth/setToken', token);
this.$store.commit('auth/updateUser', user);
this.$router.push('/');
})
}
}
}
</script>
store/index.js
const cookieFromRequest = (request, key) => {
if (!request.headers.cookie) {
return;
}
const cookie = request.headers.cookie.split(';').find(
c => c.trim().startsWith(`${key}=`)
);
if (cookie) {
return cookie.split('=')[1];
}
}
export const actions = {
nuxtServerInit({ commit, dispatch, route }, { req }){
const token = cookieFromRequest(req, 'token');
if (!!token) {
commit('auth/setToken', token);
}
}
};
middleware/check-auth.js
export default async ({ $axios, store }) => {
const token = store.getters['auth/token'];
if (process.server) {
if (token) {
$axios.defaults.headers.common.Authorization = `Bearer ${token}`;
} else {
delete $axios.defaults.headers.common.Authorization;
}
}
if (!store.getters['auth/check'] && token) {
await store.dispatch('auth/fetchUser');
}
}
store/auth.js
import Cookie from 'js-cookie';
export const state = () => ({
user: null,
token: null
});
export const getters = {
user: state => state.user,
token: state => state.token,
check: state => state.user !== null
};
export const mutations = {
setToken(state, token){
state.token = token;
},
fetchUserSuccess(state, user){
state.user = user;
},
fetchUserFailure(state){
state.user = null;
},
logout(state){
state.token = null;
state.user = null;
},
updateUser(state, { user }){
state.user = user;
}
}
export const actions = {
saveToken({ commit }, { token, remember }){
commit('setToken', token);
Cookie.set('token', token);
},
async fetchUser({ commit }){
try{
const { data } = await this.$axios.get('/auth/user');
commit('fetchUserSuccess', data);
}catch(e){
Cookie.remove('token');
commit('fetchUserFailure');
}
},
updateUser({ commit }, payload){
commit('updateUser', payload);
},
async logout({ commit }){
try{
await this.$axios.delete('/auth/authorizations');
}catch(e){}
Cookie.remove('token');
commit('logout');
}
}
plugins/axios.js
export default ({ $axios, store }) => {
$axios.setBaseURL('http://example.com/api');
const token = store.getters['auth/token'];
if (token) {
$axios.setToken(token, 'Bearer')
}
$axios.onResponseError(error => {
const { status } = error.response || {};
if (status === 401 && store.getters['auth/check']) {
store.commit('auth/logout');
}
else{
return Promise.reject(error);
}
});
}
Then you can do what you want in your middleware, such as check auth
middleware/auth.js
export default function ({ store, redirect }){
if (!store.getters['auth/check']) {
return redirect(`/login`);
}
}
I am trying to catch an error in the controller and send status(500) to the front-end to let the user know that there is a streaming error. But for some reason the error is not caught and I am sending status(200) to the user. Let me know if i am doing something wrong.
file - utils.js
import WebSocket from 'ws';
import Twitter from 'twitter-lite';
import ck from 'ckey';
export const stream = (term, clients, twitterStream) => {
try {
const twitter = new Twitter({
// subdomain: 'api', // "api" is the default (change for other subdomains)
// version: '1.1', // version "1.1" is the default (change for other subdomains)
version: '2', // version "1.1" is the default (change for v2)
extension: false, // true is the default (this must be set to false for v2 endpoints)
consumer_key: ck.TWITTER_CONSUMER_KEY,
consumer_secret: ck.TWITTER_CONSUMER_SECRET,
access_token_key: ck.TWITTER_ACCESS_TOKEN_KEY,
access_token_secret: ck.TWITTER_ACCESS_TOKEN_SECRET,
});
let stream = twitter.stream('statuses/filter', { track: term });
new Promise(function (resolve, reject) {
stream.on('data', function (tweet) {
console.log('tweet');
resolve(broadcast(clients, JSON.stringify(tweet)));
});
stream.on('error', function (error) {
reject(error);
});
}).catch(function (e) {
console.log('stream error catch: ', e);
// throw e;
});
twitterStream = stream;
return twitterStream;
} catch (error) {
console.log('error from util', error);
// throw error;
}
};
const broadcast = (clients, message) => {
clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send(message);
}
});
};
controller
import { stream } from './utils.js';
let twitterStream;
// Sets search term for twitter stream.
export const setSearchTerm = (req, res) => {
try {
const { term } = req.params;
console.log('setSearchTerm');
console.log('term: ', term);
if (twitterStream) {
console.log('getTweetPause');
twitterStream.destroy();
}
twitterStream = stream(term, req.app.locals.clients, twitterStream);
res.status(200).json({ message: 'Successful search request' });
} catch (error) {
res.status(500).json({ message: error });
}
};
file - utils.js
import WebSocket from 'ws';
import Twitter from 'twitter-lite';
import ck from 'ckey';
export const stream = (term) => {
const twitter = new Twitter({
// subdomain: 'api', // "api" is the default (change for other subdomains)
// version: '1.1', // version "1.1" is the default (change for other subdomains)
version: '2', // version "1.1" is the default (change for v2)
extension: false, // true is the default (this must be set to false for v2 endpoints)
consumer_key: ck.TWITTER_CONSUMER_KEY,
consumer_secret: ck.TWITTER_CONSUMER_SECRET,
access_token_key: ck.TWITTER_ACCESS_TOKEN_KEY,
access_token_secret: ck.TWITTER_ACCESS_TOKEN_SECRET,
});
let stream = twitter.stream('statuses/filter', { track: term });
return stream;
};
export const broadcast = (clients, message) => {
clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send(message);
}
});
};
controller
import { stream, broadcast } from './utils.js';
let twitterStream;
// Sets search term for twitter stream.
export const setSearchTerm = async (req, res) => {
try {
const { term } = req.params;
console.log('setSearchTerm');
console.log('term: ', term);
if (twitterStream) {
console.log('getTweetPause');
twitterStream.destroy();
}
const currentStream = stream(term);
twitterStream = currentStream;
await new Promise((resolve, reject) => {
currentStream.on('data', function (tweet) {
console.log('tweets: ');
broadcast(req.app.locals.clients, JSON.stringify(tweet));
resolve(tweet);
});
currentStream.on('error', function (error) {
reject(error);
});
});
res.status(200).json({ message: 'Successful HTTP request' });
} catch (error) {
console.log('error catch: ');
res.status(500).json({ message: error });
}
};
I am new to react native and making service call for the first time. My problem is service call is not going and getting warning like
Possible unhandled Promise Rejection, Reference error: response is not defined.
I am trying to hit loginUser function.
Api.js
const BASE_URL = "http://localhost:8200";
export const api = async (url, method, body = null, headers = {}) => {
try {
const endPoint = BASE_URL.concat(url);
const reqBody = body ? JSON.stringify(body) : null;
const fetchParams = {method, headers};
if((method === "POST" || method === "PUT") && !reqBody) {
throw new Error("Request body required");
}
if(reqBody) {
console.log("ReQBody--->"+reqBody);
fetchParams.headers["Content-type"] = "application/json";
fetchParams.body = reqBody;
}
const fetchPromise = await fetch(endPoint, fetchParams);
const timeOutPromise = new Promise((resolve, reject) => {
setTimeout(() => {
reject("Request Timeout");
}, 3000);
});
const response = await Promise.race([fetchPromise, timeOutPromise]);
return response;
} catch (e) {
return e;
}
}
export const fetchApi = async (url, method, body, statusCode, token = null, loader = false) => {
console.log("In FetchAPi Function");
try {
const headers = {}
const result = {
token: null,
success: false,
responseBody: null
};
if(token) {
headers["securityKey"] = token;
}
const response = await api(url, method, body, headers);
console.log("fetchApi-->>"+response);
if(response.status === statusCode) {
result.success = true;
let responseBody;
const responseText = await response.text();
try {
responseBody = JSON.parse(responseText);
} catch (e) {
responseBody = responseText;
}
result.responseBody = responseBody;
return result;
}
let errorBody;
const errorText = await response.text();
try {
errorBody = JSON.parse(errorText);
} catch (e) {
errorBody = errorText;
}
result.responseBody = errorBody;
console.log("FetchApi(Result)--->>"+result);
throw result;
} catch (error) {
return error;
}
}
auth.actions.js
export const loginUser = (payload) => {
console.log("In LoginUser function2");
return async (dispatch) => {
<-----**I am not able to enter into this block**------>
try {
dispatch({
type: "LOGIN_USER_LOADING"
});
console.log("In LoginUser function3");
const response = await fetchApi("/login", "POST", payload, 200);
if(response.success) {
dispatch({
type: "LOGIN_USER_SUCCESS",
});
dispatch({
type: "AUTH_USER_SUCCESS",
token: response.token
});
dispatch({
type: "GET_USER_SUCCESS",
payload: response.responseBody
});
return response;
} else {
throw response;
}
} catch (error) {
dispatch({
type: "LOGIN_USER_FAIL",
payload: error.responseBody
});
return error;
}
}
}
In console log, I can't see anything in network tab. In the android emulator, the mentioned warning has come.
My console tab
I see that your BASE_URL is served using an http endpoint. You can only make requests to https endpoints from react native projects. A possible workaround is to use ngrok. Just download it and run ./ngrok http 8200 since your port number is 8200. It will expose an HTTPS endpoint and replace your BASE_URL with that link and try fetching the data again.
I use the following code to make API calls. See if you can integrate it in your code. it is quite simple:
In a class called FetchService:
class FetchService {
adminAuth(cb, data) {
console.log('here in the fetch service');
return fetch(
baseURL + "login",
{
method: "POST",
headers: {
Accept: "application/json",
},
body: data
}
)
.then((response) => response.json())
.then(responsej => {
cb(null, responsej);
})
.catch(error => {
cb(error, null);
});
}
}
export default FetchService;
Then call it from your component using:
import FetchService from './FetchService';
const fetcher = new FetchService;
export default class LoginScreen extends React.Component {
fetchData() {
const data = new FormData();
data.append('username',this.state.username);
data.append('password',this.state.password);
fetcher.wastereport((err, responsej) => {
if(err) {
//handle error here
} else {
//handle response here
}
}, data);
}
}
I have a pretty basic React App which the user can login and hit some MS Graph endpoint(s), this works great no problem once consent has been approved by the user. I also have another request firing to an anonymous Azure Function that spits back some JSON, brilliant no problem.
The issue I'm having is related to when I'm trying to make a request to an Azure Function Api that is locked down using AD with the MSAL.js lib.
I'm using https://github.com/sunilbandla/react-msal-sample.
App.js
import React, { Component } from 'react';
import './App.css';
import AuthService from './services/auth.service';
import GraphService from './services/graph.service';
import HelloService from './services/hello.service';
class App extends Component {
constructor() {
super();
this.authService = new AuthService();
this.graphService = new GraphService();
this.helloService = new HelloService();
this.state = {
user: null,
userInfo: null,
apiCallFailed: false,
loginFailed: false
};
}
componentWillMount() {}
callAPI = () => {
this.setState({
apiCallFailed: false
});
this.authService.getToken().then(
token => {
this.graphService.getUserInfo(token).then(
data => {
this.setState({
userInfo: data
});
},
error => {
console.error(error);
this.setState({
apiCallFailed: true
});
}
);
},
error => {
console.error(error);
this.setState({
apiCallFailed: true
});
}
);
};
callHelloAPI = () => {
this.setState({
apiCallFailed: false
});
this.authService.getToken().then(
token => {
this.helloService.callApi(token).then(
data => {
this.setState({
userInfo: data
});
console.log(data);
},
error => {
console.error(error);
this.setState({
apiCallFailed: true
});
}
);
},
error => {
console.error(error);
this.setState({
apiCallFailed: true
});
}
);
};
getTheToken = () => {
console.log('Get Token:');
this.authService.getToken().then(token => {
console.log(token);
});
}
logout = () => {
this.authService.logout();
};
login = () => {
this.setState({
loginFailed: false
});
this.authService.login().then(
user => {
if (user) {
console.log(user);
this.setState({
user: user
});
} else {
this.setState({
loginFailed: true
});
}
},
() => {
this.setState({
loginFailed: true
});
}
);
};
render() {
let templates = [];
if (this.state.user) {
templates.push(
<div key="loggedIn">
<button onClick={this.callAPI} type="button">
Call MS Graph
</button>
<button onClick={this.callHelloAPI} type="button">
Call Azure Function
</button>
<button onClick={this.getTheToken}>
Get The Token (JWT / Cookie)
</button>
<button onClick={this.logout} type="button">
Logout
</button>
<h3>Hello {this.state.user.name}</h3>
<h4>{this.state.user.displayableId}</h4>
</div>
);
} else {
templates.push(
<div key="loggedIn">
<button onClick={this.login} type="button">
Login with Microsoft
</button>
</div>
);
}
if (this.state.userInfo) {
templates.push(
<pre key="userInfo">{JSON.stringify(this.state.userInfo, null, 4)}</pre>
);
}
if (this.state.loginFailed) {
templates.push(<strong key="loginFailed">Login unsuccessful</strong>);
}
if (this.state.apiCallFailed) {
templates.push(
<strong key="apiCallFailed">Graph API call unsuccessful</strong>
);
}
return (
<div className="App">
<header className="App-header">
<h1 className="App-title">React app with MSAL.js</h1>
</header>
{templates}
</div>
);
}
}
export default App;
auth.service
import * as Msal from 'msal';
export default class AuthService {
constructor() {
let PROD_REDIRECT_URI = 'http://localhost:3000/';
let redirectUri = window.location.origin;
if (window.location.hostname !== '127.0.0.1') {
redirectUri = PROD_REDIRECT_URI;
}
this.applicationConfig = {
clientID: 'xxxx-xxxxx-xxxxx-xxxx',
graphScopes: ['user.read','user.readbasic.all']
};
this.app = new Msal.UserAgentApplication(
this.applicationConfig.clientID,
'',
() => {
// callback for login redirect
},
{
redirectUri
}
);
}
login = () => {
return this.app.loginPopup(this.applicationConfig.graphScopes).then(
idToken => {
const user = this.app.getUser();
if (user) {
return user;
} else {
return null;
}
},
() => {
return null;
}
);
};
logout = () => {
this.app.logout();
};
getToken = () => {
return this.app.acquireTokenSilent(this.applicationConfig.graphScopes).then(
accessToken => {
return accessToken;
},
error => {
return this.app
.acquireTokenPopup(this.applicationConfig.graphScopes)
.then(
accessToken => {
return accessToken;
},
err => {
console.error(err);
}
);
}
);
};
}
graph.service
export default class GraphService {
constructor() {
this.graphUrl = 'https://graph.microsoft.com/v1.0/users';
}
getUserInfo = token => {
const headers = new Headers({ Authorization: `Bearer ${token}` });
const options = {
headers
};
return fetch(this.graphUrl, options)
.then(response => response.json())
.catch(response => {
throw new Error(response);
});
};
}
hello.service
export default class HelloService {
constructor() {
this.graphUrl = 'https://xxx.azurewebsites.net/api/Hey';
}
callApi = token => {
const headers = new Headers({ Authorization: `Bearer ${token}` });
const options = {
headers
};
return fetch(this.graphUrl, options)
.then(response => response.json())
.catch(response => {
throw new Error(response);
});
};
}
Calling this hello.service works fine anonymously but returns a 401 when locked down by an Azure AD App. I've verified the JWT token from jwt.io also. I'm guessing the problem is an auth issue (hopefully a simple one), would an issue arise depending if the app is an Azure AD only app or a converged app? I have also enabled CORS on the function app itself.
My brain has frozen at this point & I'm not sure which direction facing. Any help would be greatly appreciated thanks in advance.