AngularFire2 - using access token from Google Auth for Google APIs - angularjs

Google Authentication through AngularFire2 returns the Firebase access token, but not the Google access token for use on Google APIs. What's the proper way to get the access token from the AngularFire2 auth?
Angular: 2.4.9
Firebase: 3.5.2
AngularFire: 2.0.0-beta.8
Here's a plunkr:
http://plnkr.co/edit/qIbtcp?p=preview
You'll notice in the constructor:
constructor(af: AngularFire, public auth$: AngularFireAuth, public http:Http) {
auth$.subscribe((state: FirebaseAuthState) => {
if(state){
this.signedIn = true
}
});
firebase.auth()
.getRedirectResult()
.then((result) => {
console.log('result', result);
if (result.credential) {
// This gives you a Google Access Token.
var token = result.credential.accessToken;
console.log('token',token)
this.getPeople(token)
.subscribe(
people => console.log('people',people),
error => console.log(error));
}
var user = result.user;
})
.catch(err => console.log(err));
}
Where I call firebase.auth() is where I try to get the Google Access Token. However on first login, I get this error:
{
error: {
code: 403,
message: "Request had insufficient authentication scopes.",
status: "PERMISSION_DENIED"
}
}
I know this shouldn't happen because I tried the same setup with strictly Firebase (no AngularFire2), in this example:
https://embed.plnkr.co/zxOfRZ1PDDb7ee5qzIKW/
So is there an issue with sharing auth tokens between AngularFire and just Firebase? Does anyone have an example of this working?

Found a similar issue on StackOverflow:
Using Firebase Auth to access the Google Calendar API
I ended up using the same approach, it seems that you need to manually use the Google API's Javascript client, and use that credential to sign in with Firebase.

Related

Github Rest API not fetching results on hosting

I am supposed to use GITHUB REST API to fetch details such as username and repositories of a user. I am getting the results on localhost and when I deploy this project using VERCEL the project is hosted fine. The problem is that in the hosted URL the I am not able to see the results that were supposed to be fetched by the API. This is the error in the console:
GEThttps://api.github.com/users/Xaid-vfx/repos?page=1&per_page=8 [HTTP/2 401 Unauthorized 581ms]
Uncaught (in promise) HttpError: Bad credentials
What I understood is that my Authorisation key is not working whenever I am trying to deploy using vercel.
Here's the code that I am using to make API calls
const octokit = new Octokit({
auth: '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'
});
useEffect(() => {
async function get() {
setloading(true);
const req1 = await octokit.request('GET /users/{username}/repos?page=1&per_page=1000', {
username: username
})
setsize(req1.data.length)
console.log(req1.data.size);
const details = await octokit.request('GET /users/{username}', {
username: username
})
// console.log(details);
setloading(false)
return [details.data]
}
if (username != '') {
get().then(function (res) {
// setrep(res[0]);
console.log(res[0]);
setname(res[0].login);
seturl(res[0].avatar_url);
setbio(res[0].bio);
setlink(res[0].html_url)
})
}
}, [count])
This code is working fine on localhost and giving the results . When I deploy using vercel from GitHub, it does not fetch results on localhost as well as the deployed url. This has something to do with authorisation token

Why do I still need CSRF token for Laravel Sanctum Token Auth?

I am creating a chatting application. I use React for frontend and Laravel Sanctum for api auth.
I used SPA auth for api. But when I deployed it to Heroku, Heroku didn't allow the application to set cookies. So, I am trying to change my SPA auth to Token based auth.
The backend is working when I test with postman. Every routes are working. But when I call the api from my React app, it's saying [419] CSRF token mismatch.
Is there anything to configure my React app to fix this problem?
Why do I still need CSRF token for token based auth?
In case if you need to check my codes, I will add them below.
React
axios.post("https://www.mybackend.com/api/v1/login", {
email: "user_1#gmail.com",
password: "password"
});
Laravel
public function login(LoginRequest $request)
{
try {
if (Auth::attempt($request->only("email", "password"))) {
return $this->successResponse([
"user" => Auth::user(),
"token" => Auth::user()->createToken(Auth::user()->id)->plainTextToken
]);
}
return $this->failResponse([
"message" => "Wrong login credentials."
], 401);
} catch (Exception $e) {
throw new InternalErrorException($e);
}
}
api.php
Route::group(["prefix" => "v1"], function () {
Route::post("login", [\App\Http\Controllers\Api\V1\AuthController::class, "login"]);
})

Calling an Azure AD secured Azure Function from React SPA/Azure Static Web App

I'm developing an SPA with React that is hosted as an Azure Static Web App. The App is secured with Azure AD Authentication which works great, I already built a Login that works fine and I can call Azure (Graph) APIs with the token I got and retrieve information for the granted scopes (e.g. user profile picture). To achieve this, I'm using a wrapper called React AAD MSAL which neatly wraps the Microsoft Authentication Library (msal#1.4.0).
So far so good, no problems here. But I'm in need of a backend, of course. I decided to this with Azure Functions, since serverless is the best way for me here. So I made a quick HTTP trigger protoype that runs in Azure as Azure Function und works when I call the URL with the correct paramters.
But of course the Azure Function needs to be secured, so only my React App can call this function. So I thought there should be way to do this through Azure AD, since my user is already logged in as such.
I tried and tried and tried different ways I found online but none of them seem to work or I am doing something wrong.
The general tutorial I tried to follow is this one from MS itself. I tried using the "Express" setting which of course didn't work. I tried the advanced configuration, which also didn't work. The advanced tutorial says you need to have an App registration for the service, I'm not even sure if this is can be my Static Web App or a new on (I tried both with no success). Isn't it enough to tell the Azure Function that it is now AAD secured and may only accept calls from a source secured by an access token that contains the App ID of my app, which is provided in the settings? You can easily provide all these settings, it just doesn't seem to work.
So I'm stalling very early on here. To call the function itself, I first need to get a Authorization Token. According to this tutorial from MS (see "Validate tokens from providers"), I need to send an access token which I got when logging in to my SPA Web App to the Azure Function endpoint ending in .auth/login/aad. Getting this token is easy, since React AAD MSAL provides a method authProvider.getAccessToken() which I can use to extract it. I'm then making a POST request to https://<My Azure Function URI>/.auth/login/aad with the access token in the body as JSON { 'access_token': authToken.accessToken }. I should be getting an Authentication Token which I can then use to call the actual function, but I always get the same response, no matter what I try: You do not have permission to view this directory or page.
So this is where I am. I tried different methods and solutions I found to no avail. Maybe I did something wrong from the ground up, maybe I'm using the wrong methods, I really don't know at this point. Does anyone have experience with this? Is there something wrong in my general approach, do I need to do something else? Or is it just something in the configuration I need to change?
Edit
Since it was asked, here's how I retrieve the token. The concept behind this is using a redux-thunk to dispatch an asynchronous action to the react-redux store. I simplified it not only for this question here but for my testing as well. Right now I'm only trying to get the authentication token and log the answer the POST request is giving me:
import { authProvider } from '../../Authentication/AuthProvider';
//Fetch
async function getAccessToken(authToken) {
const body = { 'access_token': authToken.accessToken };
fetch('https://<My Azure function URL>/.auth/login/aad', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(body)
},
).then(response => {
console.log(response);
});
}
export const fetchAddressData = () => async dispatch => {
const token = await authProvider.getAccessToken();
await getAccessToken(token);
// The actual call to the Azure function will go here once we have an Authentication Token
}
The authProvider is a component from react-aad msal and the configuration looks like this:
import { MsalAuthProvider, LoginType } from 'react-aad-msal';
//MSAL Config
const config = {
auth: {
authority: '<Tenant ID>',
clientId: '<Client ID from App registration (Azure Static Web App)>',
redirectUri: window.location.origin
},
cache: {
cacheLocation: "localStorage",
storeAuthStateInCookie: true
}
};
// Authentication Parameters
const authenticationParameters = {
scopes: [
'openid',
'user.read',
'https://<Azure Function URI>/user_impersonation'
],
forceRefresh: true
}
// Options
const options = {
loginType: LoginType.Redirect,
tokenRefreshUri: window.location.origin
}
export const authProvider = new MsalAuthProvider(config, authenticationParameters, options)
Edit 2
I tweaked some additional settings trying to work with the user impersonation, still no success. Here's an overview over my current Azure settings that are important for this (did I forget any?).
Azure Function:
Authentication is activated, AAD auth only, advanced settings:
Azure Function - App Registration:
Authentication settings:
Client secret:
Expose an API - Exposing user_impersonation API so the Web App can consume it:
Azure Static Web App (React SPA) - App Registration:
Application URI ID which is used as Token Audience in the Azure Function (advanced authentication setting):
API permissions - using the user_impersonation API which is exposed by the Azure Function App Registration:
Is there anything wrong in this configuration? It mostly likely is, but I don't know what since I followed the tutorial on MSDN. I only added the user_impersonation afterwards since it didn't work.
According to the information provided, you do not configure right scope in your authProvider file. You need to add the scope you define when you create AD application to protect function. So please update the scope as scopes: ["openid","<your function app scope>"] in authProvider.
For example
Create Azure AD application to protect function
Register Azure AD application. After doing that, please copy Application (client) ID and the Directory (tenant) ID
Configure Redirect URI. Select Web and type <app-url>/.auth/login/aad/callback.
Enable Implicit grant flow
Define API scope and copy it
Create client secret.
Enable Azure Active Directory in your App Service app
Create Client AD application to access function
Register application
Enable Implicit grant flow
configure API permissions. Let your client application have permissions to access function
Code
authProvider
import { MsalAuthProvider, LoginType } from "react-aad-msal";
import { Logger, LogLevel } from "msal";
export const authProvider = new MsalAuthProvider(
{
auth: {
authority: "https://login.microsoftonline.com/<tenant>",
clientId: "<>",
postLogoutRedirectUri: window.location.origin,
redirectUri: window.location.origin,
validateAuthority: true,
navigateToLoginRequestUrl: false,
},
system: {
logger: new Logger(
(logLevel, message, containsPii) => {
console.log("[MSAL]", message);
},
{
level: LogLevel.Verbose,
piiLoggingEnabled: false,
}
),
},
cache: {
cacheLocation: "sessionStorage",
storeAuthStateInCookie: true,
},
},
{
scopes: [
"openid",
"<the scope you define for your function>",
],
forceRefresh: true,
},
{
loginType: LoginType.Popup,
tokenRefreshUri: window.location.origin + "/auth.html",
}
);
Call API
const CallAPI= async () => {
// You should should use getAccessToken() to fetch a fresh token before making API calls
const authToken = await provider.getAccessToken();
console.log(authToken.accessToken);
let body = { access_token: authToken.accessToken };
let res = await fetch(
"<your function url>/.auth/login/aad",
{
method: "POST",
mode: "cors",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body),
}
);
let data = await res.json();
console.log(data);
body = { name: "Azure" };
res = await fetch("<>", {
method: "POST",
mode: "cors",
headers: {
"Content-Type": "application/json",
"X-ZUMO-AUTH": data["authenticationToken"],
},
body: JSON.stringify(body),
});
data = await res.text();
console.log(data);
};
I was dealing with the same issue for a while. If your sure you are getting the right access token and and passing it correctly, then look into the configuration in the portal. If you automatically created the app registration for the function app, Check how the ISSUER URL is set up. You can find this in the function app>authentication>edit. make sure that the url does not have /v2.0 at the end. Azure function only work with the default(/v1.0) route.

'Invalid Signature' error for Access Token (azure active directory / msal js)

I used MSAL JS for authenticating user & thereafter calling acquireTokenPopup(scopes) for Access Token.
I am getting the access token, but cannot use it as it says Invalid Signature.
(checked in jwt.io too - same error)
Over the forum I found it is due to Graph adding nonce.
What will be the solution?
Please help.
Following is the code.
tenantConfig = {
scopes: ["directory.read.all"]
};
this.clientApplication.acquireTokenSilent(this.tenantConfig.scopes).then(
function (accessToken) {
},
function (error) {
console.log(error);
this.clientApplication
.acquireTokenPopup(this.tenantConfig.scopes)
.then(
function (accessToken) {
console.log("access token " + accessToken);
},
function (error) {
alert(error);
}
);
}
);
Your scopes parameter should be "[CLIENT_ID]/.default" When using MSAL.js and if you are not using graph api:
var requestObj = {
scopes:["[CLIENT_ID]/.default"]
};
If you intent to use the graph api the scopes parameter is different:
var ResourceId = "https://graph.windows.net/";
var scopes = [ ResourceId + "Directory.Read", ResourceID + "Directory.Write"];
The example here https://learn.microsoft.com/en-us/azure/active-directory/develop/tutorial-v2-javascript-spa uses graph api and generate a specific token for graph api, change the scopes parameter if you need to generate an access token for other uses.
More information on scopes parameter: https://learn.microsoft.com/en-us/azure/active-directory/develop/msal-v1-app-scopes#scopes-to-request-access-to-all-the-permissions-of-a-v10-application
This doesn't matter. Just change the algorithm to HS256 in jwt.io, then the signature will be verified.
The access token should be ok. Just make sure you have added Diretory.Read.All permission on Azure portal and granted admin consent.
'
Reference:
Call Graph API from a JavaScript Single Page Application using msal.js

Token API and Backend Google OAuth in Node and Angular

We are transitioning from an API using cookies for state (ExpressJS sessions) to a stateless (token) API.
We use a single PassportJS authentication strategy (GoogleStrategy). When the OAuth flow completes, Google calls back to a backend route with an access token.
Previously, we would set a cookie at this point using req.session and redirect the user to our dashboard.
With a token API, we generate a token based on the email (acting as a username) and access token (acting as password) when Google calls back to the backend route.
How do we pass this token to the front-end (Angularjs) so that it can make authenticated requests?
Do we need to switch to Google's front-end OAuth APIs?
One way to pass the token to a client-side web application is to put the signed JSON web token into the cookie , which your client-side app can access and use (either appending the token to every GET request or using it in your web socket authentication). Just to be clear, you're no longer using cookies as a reference for server-recorded state, instead you're are simply using them as a storage mechanism that both client and server can access, where you can store your encoded token.
Here's a great example from the generator-angular-fullstack:
In the router, receiving the callback from the google authentication:
.get('/callback', passport.authenticate('google', {
failureRedirect: '/signup',
session: false
}), auth.setTokenCookie);
And the setTokenCookie function:
function setTokenCookie(req, res) {
if (!req.user) return res.json(404, { message: 'Something went wrong, please try again.'});
var token = signToken(req.user._id, req.user.role);
res.cookie('token', JSON.stringify(token));
res.redirect('/');
}
And the signToken function:
function signToken(id) {
return jwt.sign({ _id: id }, config.secrets.session, { expiresInMinutes: 60*5 });
}

Resources