Teams Tab App not working on mobile client - teams-toolkit

I have a teams app which serves as another front end for our application (I will call it App 1) and we just use the client id for App 1 to authenticate. This works fine on Teams desktop and web, but on teams mobile (Android) I can successfully obtain a bearer token, but the rest of the api calls return status cancelled.
My login work flows look like so:
LoginForm.js
const { teamsUserCredential } = useContext(TeamsFxContext);
const { loading, error, data, reload } = useGraphWithCredential(
async (graph, teamsUserCredential, scope) => {
const provider = new TeamsFxProvider(teamsUserCredential, scope);
Providers.globalProvider = provider;
Providers.globalProvider.setState(ProviderState.SignedIn);
if (teamsUserCredential.ssoToken === null) {
setTeamsLoginError(true); // flag to switch to web auth flow
}
if (error) {
setTeamsLoginError(true);
}
},
{ scope: ["User.Read"], credential: teamsUserCredential }
);
// for web auth flow
const onClick = async () = {
await login(instance)
}
App.js
const { theme, themeString, teamsUserCredential, error, loading } =
useTeamsUserCredential({
initiateLoginEndpoint:
"https://{teams app site name}.web.core.windows.net/auth-start.html",
clientId: "{client id for App 1}", // not the teams app client id
});
const {
instance,
accounts,
} = useMsal();
// SSO auth flow
if (!teamsLoginError) {
let newAccessToken;
try {
newAccessToken = await teamsUserCredential.getToken(
"api://{client id for App 1}/access_as_user"
);
} catch (error) {
console.log("error getting token");
}
const token = `Bearer ${newAccessToken.token}`;
}
// auth flow for web clients
else {
const accessTokenRequest = {
scopes: ["api://{client id for App 1}/access_as_user"],
account: accounts[0],
};
instance
.acquireTokenSilent(accessTokenRequest)
.then(async (accessTokenResponse) => {
let newAccessToken = accessTokenResponse.accessToken;
const token = `Bearer ${newAccessToken}`;
}

Related

How to do queuing graphql calls using ApolloClient in next.js?

Ex.
const clientRef = useRef(initClient());
function initClient() {
const authLink = setContext(async (\_, options) =\> {
const {
headers =
{
‘Accept-Language’: ‘en’ }
} = options;
headers.Authorization = Bearer ${token};
return { headers };
});
const client = new ApolloClient({
link: ${url},
cache: new InMemoryCache(),
defaultOptions,
});
return client;
}
Here is my configuration and here is my query and mutation:
const handleQuery = async (params) =\> {
const res = await clientRef.current.query(params);
const { data, errors } = res;
if (errors) {
checkErrorForUnauthenticated(errors);
}
return { data };
};
const handleMutation = async (params) =\> {
const res = await clientRef.current.mutate(params);
const { data, errors } = res;
if (errors) {
checkErrorForUnauthenticated(errors);
}
return { data };
};
Problem: I have 3 apis on HOC and 5 apis in child component. So when access token expires after 1 API call, I have to call another endpoint to get access token and then want to call remain apis.
But now problem is while doing call for refresh token other apis are fired with old token and got error.
How can I queue the remaining calls while refresh token is being called?
5 apis are calling after 1st api call is access token expire. I'm calling for refreshToken api meanwhile other apis are calling. I want other apis call to be pause and resume after refreshToken.

OAuth2 fails to return auth token using simple-oauth2 and Firebase Functions for Spotify Authentication

I have been working on a oauth2 flow for spotify by following this similar tutorial by the Firebase team for Instagram HERE
I am able to submit my credentials and return the user code and state in the url, but when I run the method to submit the code to return an auth token, the auth token that I print to console in the Firebase functions returns: Auth Token Error Not Found. Here's my workflow:
Here's the Spotify docs
FIRST, I have a function to configure my spotifyOAuth:
function spotifyOAuth2Client() {
// Spotify OAuth 2 setup
const credentials = {
client: {
id: functions.config().spotify.clientid,
secret: functions.config().spotify.clientsecret,
},
auth: {
tokenHost: 'https://accounts.spotify.com',
authorizePath: '/authorize'
},
};
return require('simple-oauth2').create(credentials);
}
I use that function in this Firebase function that is called using https://us-central1-<my project string>.cloudfunctions.net/redirect:
exports.redirect = functions.https.onRequest((req, res) => {
const oauth2 = spotifyOAuth2Client();
cookieParser()(req, res, () => {
const state = req.cookies.state || crypto.randomBytes(20).toString('hex');
console.log('Setting verification state:', state);
res.cookie('state', state.toString(), {
maxAge: 3600000,
secure: true,
httpOnly: true,
});
const redirectUri = oauth2.authorizationCode.authorizeURL({
redirect_uri: OAUTH_REDIRECT_URI,
//scope: OAUTH_SCOPES,
state: state,
});
console.log('Redirecting to:', redirectUri);
res.redirect(redirectUri);
});
});
The code above returns a url string with the proper parameters, the following code block is where my code breaks, I have another cloud function that runs after being redirected from the res.redirect(redirectUri) above. And when I try to run the getToken() method, it appears to not return anything because I hit the catch block instead? This is where I observe the Auth Token Error Not Found.
const oauth2 = spotifyOAuth2Client();
try {
return cookieParser()(req, res, async () => {
console.log('Received verification state:', req.cookies.state);
console.log('Received state:', req.query.state);
if (!req.cookies.state) {
throw new Error('State cookie not set or expired. Maybe you took too long to authorize. Please try again.');
} else if (req.cookies.state !== req.query.state) {
throw new Error('State validation failed');
}
console.log('Received auth code:', req.query.code);
console.log(OAUTH_REDIRECT_URI);
// Get the access token object (the authorization code is given from the previous step).
const tokenConfig = {
code: req.query.code,
redirect_uri: 'http://localhost:8100/popup'
};
// Save the access token
try {
const result = await oauth2.authorizationCode.getToken(tokenConfig)
const accessToken = oauth2.accessToken.create(result);
console.log('inside try');
console.log(result);
console.log(accessToken);
} catch (error) {
console.log('Access Token Error', error.message);
}
I've double checked my spotify client/secret credentials in the config, what is going wrong with this OAuth2 flow?
Resolved my issue, I was not using the correct endpoints:
const credentials = {
client: {
id: functions.config().spotify.clientid,
secret: functions.config().spotify.clientsecret,
},
auth: {
tokenHost: 'https://accounts.spotify.com',
authorizePath: '/authorize',
tokenPath: '/api/token'
},
};

Expo push notifications stopped working in production

I'm using Expo to develop both Android and iOS at same time. Notifications were working fine for several weeks, and then out of no where stopped working in production, even though I did not update the app during this time.
Server-side, everything is still fine, and notifications are being pushed. In dev, notifications are still being received and handled properly, but in production, it's crickets.
Has anyone else experienced this / what could be causing this?
Here is my code:
class Dashboard extends Component {
constructor(props) {
super(props);
this.state = {
notificationsSet: false,
}
}
componentDidMount() {
this.registerForPushNotificationsAsync(this.props.currentUser.currentUser.id, this.props.currentUser.authToken)
savePushToken = (userId, pushToken, token) => {
//API call to save push token to database
apiHelper
.savePushToken(userId, pushToken, token)
.then(res => {
return
})
.catch(err => console.log("err saving", err));
};
handleNotification = notification => {
this.props.setNotification({ notification })
}
registerForPushNotificationsAsync = async (userId, token) =>{
//requesting if user would like to turn on notifications
const { status: existingStatus } = await Permissions.getAsync(
Permissions.NOTIFICATIONS
);
//this checks if notifications is turned on for the app --- "granted"
let finalStatus = existingStatus;
if (existingStatus !== "granted") {
const { status } = await Permissions.askAsync(Permissions.NOTIFICATIONS);
finalStatus = status;
}
if (finalStatus !== "granted") {
return;
} //if "granted" then get push notifications and calls this.savepushtoken to save into the API
let pushToken = await Notifications.getExpoPushTokenAsync();
this.subscription = Notifications.addListener(this.handleNotification);
this.savePushToken(userId, pushToken, token);
};
render() {
return(...)
}
}

push event not triggered in service worker

Following this tutorial until "Handle push event" section to setup a desktop notification system in my application, I face a problem:
When I click "push" to push a notification artificially with Chrome, no notification appear. No message in the console.
I allowed the notification from the website and the service-worker is well installed in my browser.
My service worker looks like this:
self.addEventListener('push', function (event) {
console.log('[Service Worker] Push Received.')
console.log(`[Service Worker] Push had this data: "${event.data.text()}"`)
const title = 'My App Name'
const options = {
body: event.data.text(),
icon: 'pwa/icon.png',
badge: 'pwa/badge.png'
}
const notificationPromise = self.registration.showNotification(title, options)
event.waitUntil(notificationPromise)
})
and my service worker registration (using register-service-worker npm package) looks like this:
import { register } from 'register-service-worker'
const applicationServerPublicKey = 'BI5qCj0NdNvjDcBYTIXiNccdcP74Egtb3WxuaXrHIVCLdM-MwqPkLplHozlMsM3ioINQ6S_HAexCM0UqKMvaYmg'
function urlB64ToUint8Array (base64String) {
const padding = '='.repeat((4 - base64String.length % 4) % 4)
const base64 = (base64String + padding)
.replace(/\-/g, '+')
.replace(/_/g, '/')
const rawData = window.atob(base64)
const outputArray = new Uint8Array(rawData.length)
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i)
}
return outputArray
}
async function manageNotificationSubscription (registration) {
const subscription = await registration.pushManager.getSubscription()
let isSubscribed: boolean = !(subscription === null)
if (isSubscribed) {
console.log('User IS subscribed.')
} else {
console.log('User is NOT subscribed.')
const applicationServerKey = urlB64ToUint8Array(applicationServerPublicKey)
try {
await registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: applicationServerKey
})
console.log('User just subscribed.')
} catch (e) {
console.error('Failed to subscribe the user: ', e)
}
}
}
if (process.env.NODE_ENV === 'production') {
register(`${process.env.BASE_URL}service-worker.js`, {
ready () {
console.log(
'App is being served from cache by a service worker.'
)
},
async registered (registration) {
console.log('Service worker has been registered.')
await manageNotificationSubscription(registration)
},
cached () {
console.log('Content has been cached for offline use.')
},
updated () {
console.log('New content is available; please refresh.')
},
offline () {
console.log('No internet connection found. App is running in offline mode.')
},
error (error) {
console.error('Error during service worker registration:', error)
}
})
}
It looks like the push event in the service-worker is not even triggered...
Did I do something wrong?

How to authenticate user on server with firebase when they are already authenticated on client?

I have an angular app that uses firebase to authenticate users on the client. This seems to work properly.
export class AuthService {
user$: Observable<firebase.User>;
constructor(private af_auth: AngularFireAuth) {
this.user$ = this.af_auth.authState;
this.user$.subscribe(user => {
// do something with the firebase user
});
}
}
I also have some server-based stuff running in node.js with express. I would like to try to verify that the user hitting my endpoint is already authenticated with my app through firebase. Can I do this?
I'd like to have a route handler in express something like this:
var firebase_app = firebase.initializeApp(firebase_config);
auth.isAuthenticated = function (req, res, next) {
// I had seen a suggestion to do the following, but currentUser is always null here.
var user = firebase_app.auth().currentUser;
if (user !== null) {
// Authenticated with my app?
req.auth_user = user;
next();
} else {
res.status(401).send({error: 'Nope'});
}
};
How can I tell from within the express route handler that my user is logged in to my app?
Step 1 Angular. Send the Firebase Auth ID token in the header from angular to your express endpoint.
postRequest() {
const url = 'https://your-endpoint';
firebase.auth().currentUser.getIdToken()
.then(authToken => {
const headers = new Headers({'Authorization': 'Bearer ' + authToken });
return this.http.post(url, { someData } , { headers }).toPromise()
})
}
Step 2 Node. Decrypt the the auth token using the Firebase admin SDK. verifyIdToken verifies the Firebase ID token (JWT). If the token is valid, the promise is fulfilled with the token's decoded claims; otherwise, the promise is rejected.
const admin = require('firebase-admin');
admin.initializeApp(yourConfig);
const express = require('express')
const app = express()
app.post('/your-endpoint', (req, res) => {
const token = req.headers.authorization.split('Bearer ')[1]
return admin.auth().verifyIdToken(token)
.then(decodedToken => {
const uid = decodedToken.uid;
res.status(200).send('Looks good!')
})
.catch(err => res.status(403).send('Unauthorized'))
});
Sources:
https://jwt.io/
https://firebase.google.com/docs/auth/admin/verify-id-tokens
https://angularfirebase.com/lessons/secure-firebase-cloud-functions/

Resources