How to have the refresh token? - javascript

I need to use Google Play Android API, i follow a lot of instructions to be connected with the API but I block at one.(Authorization documentation)
Exactly at the step 4 when they say:
Sending a Post with this code:
grant_type=authorization_code
code=<the code from the previous step>
client_id=<the client ID token created in the APIs Console>
client_secret=<the client secret corresponding to the client ID>
redirect_uri=<the URI registered with the client ID>`
I specify i use serverless and node, how can I do to have my refresh token in https://accounts.google.com/o/oauth2/token please ?
Thank's a lot and sry for my english ^^.
Sry for this oversight, my serverless it’s just that
#serverless.yml
service: scrapper-app
provider:
name: aws
runtime: nodejs8.10
region: eu-west-3
functions:
app:
handler: index.handler
events:
- http: ANY /
- http: 'ANY {proxy+}'
and my js it’s just that too:
//index.js
const serverless = require('serverless-http');
const express = require('express')
const app = express()
//API
const { google } = require('googleapis');
const oauth2Client = new google.auth.OAuth2(
IDCLient,
Secret,
'https://accounts.google.com/o/oauth2/auth',
);
const scopes = 'https://www.googleapis.com/auth/androidpublisher';
const url = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: scopes
)}
// GET
app.get('/', function (req, res) {
res.send('Scrapper Rs!');
})
module.exports.handler = serverless(app);
I really dont know how can i do http-post using node and serverless, i succeed with a database (with curl) but not post to an url.

I didn't used Google Authentication. But I think you need to use access_type = offline
access_type Recommended. Indicates whether your application can
refresh access tokens when the user is not present at the browser.
Valid parameter values are online, which is the default value, and
offline.
Set the value to offline if your application needs to refresh access
tokens when the user is not present at the browser. This is the method
of refreshing access tokens described later in this document. This
value instructs the Google authorization server to return a refresh
token and an access token the first time that your application
exchanges an authorization code for tokens.
To set this value in PHP, call the setAccessType function:
$client->setAccessType('offline');
Source: https://developers.google.com/identity/protocols/OAuth2WebServer

Related

endpoints_resolution_error in msal react

I was trying to acquire token from our Microsoft tenant. I have no knowledge about the Azure AD or whatsoever, because I only tasked to develop front end for our Microsoft Dynamics App in React. I only got some of the credential like tenant id, client id, client secret and resource.
I used MSAL Node library and function ConfidentialClientApplication() to acquire the token
But when I check it in the Ms. Edge's console log it throw an error
{"errorCode":"endpoints_resolution_error","errorMessage":"Error: could
not resolve endpoints. Please check network and try again. Detail:
ClientAuthError: openid_config_error: Could not retrieve endpoints.
Check your authority and verify the .well-known/openid-configuration
endpoint returns the required endpoints. Attempted to retrieve
endpoints from: verify
url","subError":"","name":"ClientAuthError","correlationId":""}
When I click the veryfy url (Cannot show you the url because it might contain sensitive information)
It shows all the metadata of the open id so I thought maybe it's normal.
But why is the error endpoints_resolution_error throwed when everything is normal?
Here is some snapshot of my code
const config = {
auth: {
clientId: clientID
authority: "https://login.microsoftonline.com/{tenantID}/",
clientSecret: clientSecret,
knownAuthorities: ["login.microsoftonline.com"],
protocolMode: "OIDC"
}
};
// Create msal application object
const cca = new msal.ConfidentialClientApplication(config);
// With client credentials flows permissions need to be granted in the portal by a tenant administrator.
// The scope is always in the format "<resource>/.default"
const clientCredentialRequest = {
scopes: ["resource/.default"], // replace with your resource
};
cca.acquireTokenByClientCredential(clientCredentialRequest).then((response) => {
console.log("Response: ", response);
}).catch((error) => {
console.log(JSON.stringify(error));
});
I've tried changing the authority and the protocol mode several times, but same result

Azure AD When to use API Permissions vs Expose an API

I am currently developing a react web app that will use Microsoft's MSAL package to authenticate users to ensure only users within our tenant may access the Api.
I've built a http function app called TARGET_APP with a python function that accesses our data and returns it. I registered it to our Azure AD enterprise applications.
Now according to the documentation for proper "On Behalf Of" calls to work I am to register another app to represent my react client app, called CALLER_APP I registered this as well, and set up the scopes I need which include email, user.read, and the TARGET_APP's exposed Api.
Example of my CALLER_APP permissions here:
However when attempting to authorize with the CALLER_APP from the client, via MSAL with the scopes in the image, I get a prompt saying "Admin consent required"
Snippet from my authentication flow (handleLogin is the initiating function called) :
const msalConfig = {
auth: {
authority: "https://login.microsoftonline.com/MY_TENANT/",
clientId: "CALLER_APP_CLIENT_ID",
redirectUri,
postLogoutRedirectUri: redirectUri
},
cache: {
cacheLocation: "localStorage"
}
}
// NOTE I have subbed out my actual caller scope with "CALLER_APP_SCOPE" for this post
const loginRequest = {
scopes: ["CALLER_APP_SCOPE", "user.read", "email"]
};
async function handleLogin(instance) {
const loginUrl = await getLoginUrl(instance, loginRequest);
const loginResult = await launchWebAuthFlow(instance, loginUrl);
// Acquire token
const { accessToken } = await acquireToken(instance, loginRequest);
console.log(accessToken)
}
/**
* Generates a login url
*/
async function getLoginUrl(instance, request) {
return new Promise((resolve, reject) => {
instance.loginRedirect({
...request,
onRedirectNavigate: (url) => {
resolve(url);
return false;
}
}).catch(reject);
});
}
/**
* Generates a login url
*/
async function launchWebAuthFlow(instance, url) {
return new Promise((resolve, reject) => {
chrome.identity.launchWebAuthFlow({
interactive: true,
url
}, (responseUrl) => {
// Response urls includes a hash (login, acquire token calls)
if (responseUrl.includes("#")) {
instance.handleRedirectPromise(`#${responseUrl.split("#")[1]}`)
.then(resolve)
.catch(reject)
} else {
// Logout calls
resolve();
}
})
})
}
/**
* Attempts to silent acquire an access token, falling back to interactive.
*/
async function acquireToken(instance, request) {
return instance.acquireTokenSilent(request).then((response) => {
console.log(response.accessToken);
}).catch(async (error) => {
console.error(error);
storage.set({'loggedState': false});
});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Most of this code is taken directly from the documentation,
Calling the handleLogin function initiates the authentication flow successfully, however when I log in with my Microsoft credentials I receive the "App needs permission to access resources in your organisation that only an admin can grant" popup.
I double checked my scopes and ensured none require admin consent, as well as I have gone into the enterprise apps user consent and permissions settings and enabled user consent on low impact scopes as you can see here:
Enterprise Setting:
The "3 permissions classified as low impact" are the 3 scopes described above (email, user.read, allow-caller)
However,
If I go to the "Expose an API" blade instead for the CALLER_APP and make a scope there, and use that scope in the MSAL call instead, authentication goes through fully, I get a bearer token, and I am able to use the API for what I need.
This method is not mentioned in the documentation, nor any of the readings I've looked into though.
I was wondering if I could get help in understand why I shouldn't use "Expose an API" for my case, as well as why it requires admin consent?
Usually the permissions in the API permissions are selected where
user.read , email are graph permissions and when you mention
User.Read while calling msal it indirectly means
https://graph.microsoft.com/User.read which is the basic permission
to sign in user to read users profile and mail.
But the scope for calling your web api is created by you and it has different AppId or say App ID URI for different applications and its scope needs to be defined uniquely for that App to access that.
So actual scopes for that app to access the Api are exposed in expose an api blade which is the scope of the App to access.
NOTE:Actual full value/string of the Scope is the concatenation of your web API's Application ID URI and Scope name of scope. The
App ID URI acts as the prefix for the scopes you'll reference in your
API's code, and it must be globally unique.
For example,
if your web API's application ID URI is https://contoso.com/ and the
scope name is Employees.Read.All, the full scope is:
https://contoso.com/Employees.Read.All or
api://<application-client-id>/allow-caller in your case.
And coming to the point that it is asking admin consent is , when
there is no scope that actually means full string scope
api:///allow-caller , only mentioning
allow-caller is totally different scope and this new scope may
require consent from admin as it is not exposed for that particular
API.
Also you can add a client application in expose an api blade in case you don’t want to see the admin consent as the "authorized client applications" is used when you basically want to preauthorize users without admin consent being required to access that api ,If not it will prompt users for consent if needed.
Please check the below image:
References:
quickstart-configure-app-expose-web-api(github)
azure-expose an Api vs Api-permissions(stackOverflow)

Feathers JS authentication with no email

Im looking for an authentication system where the user submits to an enpoint and a jwt is generated at this endpoint, im not sure how to implement this, my client side application does not make use of email address or stored information, it is in fact a dApp. I just need an endpoint that will calculate a value from a supplied seed phrase and a password if the processing of these values goes well ( and it nearly always will unless someone sends junk to the endpoint) then a jwt will be issued.. so far the out of box functionality with feathers cli means that i need to use local strategy and need an email address, I cant find any demos out there on this.. anyone got any pointers ? so far my auth is pretty default
const authentication = require('#feathersjs/authentication');
const jwt = require('#feathersjs/authentication-jwt');
const local = require('#feathersjs/authentication-local');
module.exports = function (app) {
const config = app.get('authentication');
// Set up authentication with the secret
app.configure(authentication(config));
app.configure(jwt());
app.configure(local());
// The `authentication` service is used to create a JWT.
// The before `create` hook registers strategies that can be used
// to create a new valid JWT (e.g. local or oauth2)
app.service('authentication').hooks({
before: {
create: [
authentication.hooks.authenticate(config.strategies)
],
remove: [
authentication.hooks.authenticate('jwt')
]
}
});
};
and heres my service:
// Initializes the `aerAuth` service on path `/userauthendpoint`
const createService = require('feathers-memory');
const hooks = require('./userauthendpoint.hooks');
module.exports = function (app) {
const paginate = app.get('paginate');
const options = {
name: 'userauthendpoint',
paginate
};
// Initialize our service with any options it requires
app.use('/userauthendpoint', createService(options) );
// Get our initialized service so that we can register hooks and filters
const service = app.service('userauthendpoint');
service.hooks(hooks);
};
I am relatively new to feathers but not to building auth systems (in PHP)
The Custom authentication strategy guide and the feathers-authentication-custom plugin probably allow to do what you are looking for.
It also depends on how you want to implement this. You can either use the custom strategy for every service (as in the case of the API key which has to be sent in the header with every request) or just before the /authentication service to allow creating a JWT (the issue here is that it needs to reference a userId or other entityId that exists in the database which you don't have).
The easiest way would be to go with the first options and a custom header (X-DAP-PASSWORD) which could look like this:
const custom = require('feathers-authentication-custom');
app.configure(authentication(settings));
app.configure(custom((req, done) => {
const password = req.headers['x-dap-password'];
if(checkPassword(req.app.get('seedPassphrase'), password)) {
// implement your own custom logic for loading and verifying the user
done(null, user);
} else {
done(new Error('Invalid passphrase'));
}
}));

How it is supposed to auth requests from SSR to Feathers JS API?

There is examples about how to access FeathersJS API from SSR, but they lack any info on how it is supposed to authorize such requests.
Is it ok to instantiate feathers-client app for every request? Would not it be to heavy?
There is an official example of how to call feathers API from server side:
// Set up a socket connection to our remote API
const socket = io('http://api.feathersjs.com');
const api = client().configure(socketio(socket));
​
app.get('/messages', function(req, res, next){
api.service('messages')
.find({ query: {$sort: { updatedAt: -1 } } })
.then(result => res.render('message-list', result.data))
.catch(next);
});
But what if the messages service will require authenticated user?
Should i just manually get token from SSR's req and add it somehow to api instance or api.service call?
Taking in mind the asynchronous nature of node it seems that durable way here is to call client() inside the app.get '/messages' handler, is it a supposed way?
It is also unclear does one of the Feathers boilerplate examples have durable SSR authentication, i've described it here.
Here is how i got it working.
On every request SSR create an API adapter before routing:
app.use('/', (req, res, next) => {
req.api = APIClient(req);
next();
});
APIClient constructor gets token from cookie an sets it using the set('accessToken', token) method, provided by feathers-authentication-client plugin:
'use strict';
const feathers = require('feathers');
const superagent = require('superagent');
const hooks = require('feathers-hooks')
const feathers_rest = require('feathers-rest/client');
const auth_plugin = require('feathers-authentication-client');
const config = require('../config');
const host = clientUrl => (
__SERVER__ ? `http://${config.apiHost}:${config.apiPort}` : clientUrl
);
/* API adaptor constructor.
*/
module.exports = function APIClient(req) {
const api = feathers()
// REST plugin gives ability to query services over HTTP,
// superagent used as an isomorphic HTTPClient.
.configure(feathers_rest(host('/api')).superagent(superagent))
.configure(hooks())
// Auth plugin gives ability to set accessToken
.configure(auth_plugin())
;
if (__SERVER__) {
api.set('accessToken', req['cookies']['feathers-jwt']);
}
return api;
}
So, here is a page loading flow i've got:
When one type 'my-app.com' in a browser, it sends a GET request to SSR, passing an access token in feathers-jwt cookie.
SSR creates a feathers client, fetches access token from the cookie and gives it to the client by api.set('accessToken', token) method.
SSR gets data from API using this client and gives it to the template engine (pug/react etc).
SSR returns rendered page to the browser.
Also one need to set token in browser when making requests to API, because if it is on another domain there will be no cookie, and it is better to use Authorization header or token parameter when accessing API.
Discussion link.

Microsoft Graph API - 403 Forbidden for v1.0/me/events

I'm building a page with numerous calls to Microsoft Graph to different end points: to get OneDrive files, emails, user properties, etc.
The one call that does not work is to get the current user's calendar events. The end point I'm using is https://graph.microsoft.com/v1.0/me/events. The response is 403 Forbidden.
According to the Microsoft documentation here the application needs Calendars.Read or Calendars.ReadWrite permissions. I checked both of these under delegated permissions and still the same problem. I then ticked all 51 permission scopes in Azure AD for this app, and still the same problem.
I also tried creating a new app in Azure AD, but this did not help.
How can I use Microsoft Graph to get back the current user's calendar events? What am I missing?
EDIT:
I'm using ADAL.js for authentication. This is the code I have in my own doAuth function that takes in the client ID of the application.
function doAuth(clientId) {
var variables = {
// Domain of Azure AD tenant
azureAD: // the appropriate URL,
// ClientId of Azure AD application principal
clientId: clientId,
// Name of SharePoint tenant
sharePointTenant: // the appropriate URL
}
// Create config and get AuthenticationContext
window.config = {
tenant: variables.azureAD,
clientId: variables.clientId,
postLogoutRedirectUri: window.location.origin,
endpoints: {
graphApiUri: "https://graph.microsoft.com",
sharePointUri: "https://" + variables.sharePointTenant + ".sharepoint.com",
},
cacheLocation: "localStorage"
}
var authContext = new AuthenticationContext(config);
var isCallback = authContext.isCallback(window.location.hash);
authContext.handleWindowCallback();
if (isCallback && !authContext.getLoginError()) {
window.location = authContext._getItem(authContext.CONSTANTS.STORAGE.LOGIN_REQUEST);
}
var user = authContext.getCachedUser();
var token = authContext.getCachedToken(clientId);
if (!user || !token)
authContext.login();
return authContext
}
It sounds like you've changed the scopes assigned to the application. When this happens you also need to have user's reauthorize using those new scopes. To do this, add &prompt=consent to the query string of your initial ODATA redirect. This will force your new scopes to be presented to the user for authorization.
You can trigger this in the ADAL.js library using the extraQueryParameter parameter in your configuration:
// Create config and get AuthenticationContext
window.config = {
tenant: variables.azureAD,
clientId: variables.clientId,
postLogoutRedirectUri: window.location.origin,
endpoints: {
graphApiUri: "https://graph.microsoft.com",
sharePointUri: "https://" + variables.sharePointTenant + ".sharepoint.com",
},
cacheLocation: "localStorage",
extraQueryParameter: "prompt=consent"
}
In the end I wasn't able to figure this out and ended up using the Exchange API instead of Graph for mail, calendar and tasks (tasks would have required Exchange API anyway, since this is only currently available in the beta Graph API).

Categories

Resources