Want to integrate auth0 in ionic using capacitor - ionic-framework

I want to integrate auth0 in my ionic4 application. I think I am supposed to have separate implementation of auth0 for web(pwa) and android/ios. I am using capacitor and I am not able to find an appropriate solution. Is there any way in which I can maintain a single code base for all platforms?

My solution is to use Auth0 API to handle appropriate actions: Sign Up, Sign In, Sign Out and Renew Token. You can find detailed description for lots of actions at Auth0 docs.
So, I managed to create utility functions like the following one:
import environment from 'environment';
import * as constants from './constants';
const signUp = async (email: string, password: string): Promise<any> => {
const resonse = await fetch(constants.AUTH0_ENDPOINTS.SIGN_UP, {
method: 'POST',
headers: {
'Content-Type': 'application/json; charset=utf-8',
},
body: JSON.stringify({
client_id: environment.AUTH0_CLIENT_ID,
connection: constants.AUTH0_DATABASE_NAME,
email,
password,
}),
});
return resonse.json();
};
export default signUp;
Also I implemented Auth class that is responsible for session operating, refreshing token and silent auth.

Related

POST data to Google Sheet web app from AWS Lambda

CURRENTLY
I have a Google Sheets App Script 'web app'
Script in Goolge Sheets
function doPost(e) {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName("Sheet1");
sheet.getRange("A1").setValue("Hello!")
return "Success!"
}
Google Apps Script Web App Config:
Execute as: Me // or as User. I've tried both.
Who has access: Anyone within MyOrganisation
I want to make a POST request to the above Web App from AWS Lambda.
AWS Lambda .js:
const { GoogleSpreadsheet } = require("google-spreadsheet");
const doc = new GoogleSpreadsheet(
{spreadsheetId}
);
await doc.useServiceAccountAuth({
client_email: process.env.GOOGLE_SERVICE_ACCOUNT_EMAIL,
private_key: process.env.GOOGLE_PRIVATE_KEY.replace(/\\n/g, "\n"),
});
let token = doc["jwtClient"]["credentials"]["access_token"];
await new Promise((resolve, reject) => {
const options = {
host: 'script.google.com',
path: "/macros/s/{myscriptid}/exec", //<-- my web app path!
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': "Bearer "+ token
}
};
//create the request object with the callback with the result
const req = HTTPS.request(options, (res) => {
resolve(JSON.stringify(res.statusCode));
});
// handle the possible errors
req.on('error', (e) => {
reject(e.message);
});
//do the request
req.write(JSON.stringify(data));
//finish the request
req.end();
});
console.log("response:"+JSON.stringify(response))
GCP Service Account
I have a GCP Service Account, with permission to Google Sheets API, and otherwise unrestricted access.
This Service account has EDIT access to the Google Sheet with the doPost(e) script.
Token Output:
"jwtClient": {
"_events": {},
"_eventsCount": 0,
"transporter": {},
"credentials": {
"access_token": "somelongvalue...............", //<-- what I use
"token_type": "Bearer",
"expiry_date": 1661662492000,
"refresh_token": "jwt-placeholder"
},
"certificateCache": {},
"certificateExpiry": null,
"certificateCacheFormat": "PEM",
"refreshTokenPromises": {},
"eagerRefreshThresholdMillis": 300000,
"forceRefreshOnFailure": false,
"email": "serviceaccount#appspot.gserviceaccount.com",
"key": "-----BEGIN PRIVATE KEY-----\nsomelongvalue=\n-----END PRIVATE KEY-----\n",
"scopes": [
"https://www.googleapis.com/auth/spreadsheets"
],
"subject": null,
"gtoken": {
"key": "-----BEGIN PRIVATE KEY-----\nsomelongvalue=\n-----END PRIVATE KEY-----\n",
"rawToken": {
"access_token": "somelongvalue...............",
"expires_in": 3599,
"token_type": "Bearer"
},
"iss": "serviceaccount#appspot.gserviceaccount.com",
"sub": null,
"scope": "https://www.googleapis.com/auth/spreadsheets",
"expiresAt": 1661662492000
}
}
ISSUE
Current response:
response:"401"
I cannot find any Google documentation on how to setup the headers to authenticate a request (from my service account) to my organisation restricted web app.
When the Web App is open to "Anyone" then it runs fine, but as soon as I restrict to MyOrganisation, I struggle to find a way to authenticate my POST request.
HELP!
How do I set up a POST request to my Google Sheets web app such that it can be protected by authentication? Right now, I'd be happy to find ANY means to authenticate this request (not necessarily a service account) that doesn't leave it completed open to public.
Should I use this hack?
One idea I had was to put a "secret" into my lambda function, and then make the web app public. The web app would check the secret, if if matched, would execute the function.
Modification points:
In order to access Web Apps using the access token with a script, the scopes of Drive API are required to be included. Those are https://www.googleapis.com/auth/drive.readonly, https://www.googleapis.com/auth/drive, and so on. Ref
When I saw your showing script, it seems that the access token is retrieved using google-spreadsheet. When I saw the script of google-spreadsheet, it seems that this uses only the scope of https://www.googleapis.com/auth/spreadsheets. Ref
From this situation, I thought that the reason for your current issue might be due to this. If my understanding is correct, how about the following modification? In this modification, the access token is retrieved by googleapis for Node.js from the service account. Ref
Modified script:
Google Apps Script side:
function doPost(e) {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName("Sheet1");
sheet.getRange("A1").setValue("Hello!")
return ContentService.createTextOutput("Success!"); // Modified
}
When you modified the Google Apps Script, please modify the deployment as a new version. By this, the modified script is reflected in Web Apps. Please be careful about this.
You can see the detail of this in the report "Redeploying Web Apps without Changing URL of Web Apps for new IDE".
Node.js side:
const { google } = require("googleapis");
const HTTPS = require("https");
const auth = new google.auth.JWT(
"###", // Please set client_email here.
null,
"###", // Please set private_key here. When you set private_key of service account, please include \n.
["https://www.googleapis.com/auth/drive.readonly"],
null
);
function req(token) {
return new Promise((resolve, reject) => {
const data = { key1: "value1" }; // Please set your value.
const options = {
host: "script.google.com",
path: "/macros/s/{myscriptid}/exec", //<-- my web app path!
method: "POST",
headers: {Authorization: "Bearer " + token},
};
const req = HTTPS.request(options, (res) => {
if (res.statusCode == 302) {
HTTPS.get(res.headers.location, (res) => {
if (res.statusCode == 200) {
res.setEncoding("utf8");
res.on("data", (r) => resolve(r));
}
});
} else {
res.setEncoding("utf8");
res.on("data", (r) => resolve(r));
}
});
req.on("error", (e) => reject(e.message));
req.write(JSON.stringify(data));
req.end();
});
}
auth.getAccessToken().then(({ token }) => {
req(token).then((e) => console.log(e)).catch((e) => console.log(e));
});
When this script is run, when the Web Apps is correctly deployed, the script of Web Apps is run and Success! is returned.
Note:
If this modified script was not useful for your Web Apps setting, please test as follows.
Please confirm whether your service account can access to the Spreadsheet again.
Please share the email address of the service account on the Spreadsheet. From your showing Google Apps Script, I thought that your Google Apps Script is the container-bound script of the Spreadsheet.
Please reflect the latest script to the Web Apps.
When you modified the Google Apps Script, please modify the deployment as a new version. By this, the modified script is reflected in Web Apps. Please be careful about this.
You can see the detail of this in the report "Redeploying Web Apps without Changing URL of Web Apps for new IDE".
When you set private_key of service account, please include \n.
References:
Web Apps
Taking advantage of Web Apps with Google Apps Script
Added:
When you will directly put the value to the Spreadsheet using Sheets API with google-spreadsheet module, you can also use the following script.
const { GoogleSpreadsheet } = require("google-spreadsheet");
const sample = async () => {
const doc = new GoogleSpreadsheet("###"); // Please set your Spreadsheet ID.
await doc.useServiceAccountAuth({
client_email: client_email: process.env.GOOGLE_SERVICE_ACCOUNT_EMAIL,
private_key: process.env.GOOGLE_PRIVATE_KEY,
});
await doc.loadInfo();
const sheet = doc.sheetsByTitle["Sheet1"];
await sheet.loadCells("A1");
sheet.getCell(0, 0).value = "Hello!";
await sheet.saveUpdatedCells();
};
sample();
In this case, your service account is required to be able to access to the Spreadsheet. Please be careful about this.

OAuth invalid_grant error on coinbase using oauth2_client flutter package

I am using the oauth2_client package for flutter, connecting to the Coinbase API via OAuth 2.0.
From what I can tell, Coinbase uses the code flow for authentication. This is the same as Github. This is important to note because I can successfully auth into Github using the oauth2_client package for flutter.
To connect to Github I used the existing client:
import 'package:oauth2_client/oauth2_client.dart';
import 'package:meta/meta.dart';
/// Implements an OAuth2 client against GitHub
///
/// In order to use this client you need to first create a new OAuth2 App in the GittHub Developer Settings (https://github.com/settings/developers)
///
class GitHubOAuth2Client extends OAuth2Client {
GitHubOAuth2Client(
{#required String redirectUri, #required String customUriScheme})
: super(
authorizeUrl: 'https://github.com/login/oauth/authorize',
tokenUrl: 'https://github.com/login/oauth/access_token',
redirectUri: redirectUri,
customUriScheme: customUriScheme) {
accessTokenRequestHeaders = {'Accept': 'application/json'};
}
}
Then I created a method to call within the app:
void _oauthMethod() async {
//clientID
String cID = 'x';
//clientSecret
String cSecret = 'y';
OAuth2Client client = GitHubOAuth2Client(
redirectUri: 'my.app://oauth2redirect', customUriScheme: 'my.app');
AccessTokenResponse tknResp = await client.getTokenWithAuthCodeFlow(
clientId: cID, clientSecret: cSecret, scopes: ['repo']);
http.Response resp = await http.get('https://api.github.com/user/repos',
headers: {'Authorization': 'Bearer ' + tknResp.accessToken});
}
Calling this function brings up the OAuth page for Github, I can sign in, and if I print resp it shows a list of my repos. As expected.
Using the same method for Coinbase, I first create the new class:
class MyOAuth2Client extends OAuth2Client {
MyOAuth2Client(
{#required String redirectUri, #required String customUriScheme})
: super(
authorizeUrl:
'https://www.coinbase.com/oauth/authorize', //Your service's authorization url
tokenUrl:
'https://api.coinbase.com/oauth/token', //Your service access token url
redirectUri: redirectUri,
customUriScheme: customUriScheme) {
this.accessTokenRequestHeaders = {'Accept': 'application/json'};
}
}
Then I create the method to call:
void _coinbaseAuth() async {
String cID = 'x';
String cSecret = 'y';
MyOAuth2Client client = MyOAuth2Client(
redirectUri: 'my.app://oauth2redirect', customUriScheme: 'my.app');
AccessTokenResponse tknResp = await client.getTokenWithAuthCodeFlow(
clientId: cID, clientSecret: cSecret, scopes: ['wallet:user:read']);
print(tknResp);
//code fails
//http.Response resp =
// await http.get('https://api.coinbase.com/v2/user', headers: {
// 'Authorization': 'Bearer ' + tknResp.accessToken,
// 'Content-Type': 'application/json',
// 'Charset': 'utf-8'
// });
}
I can't run the http.Response part, because it is filled with nulls. The tknResp prints:
HTTP 401 - invalid_grant The provided authorization grant is invalid,
expired, revoked, does not match the redirection URI used in the
authorization request, or was issued to another client.
I have tried creating a new OAuth application in Coinbase, however this doesn't work.
Does anyone know why I'm getting this error? It's confusing for me as the code worked with Github using the exact same OAuth flow.
I tested the auth flow manually using postman, which enabled me to get the token.
After some testing, I was able to get the token with the dart package by adding the extra auth code params & disabling PKCE
AccessTokenResponse tknResp = await client.getTokenWithAuthCodeFlow(
clientId: cID,
clientSecret: cSecret,
scopes: ["wallet:user:read"],
authCodeParams: {
"grant_type": "authorization_code",
"redirect_uri": "my.app://oauth2redirect"
},
enablePKCE: false,
state: 'OYWjs_95M6jlkvy5');
hi in my case i have problems in the get token with duplicate oauth of coinbase with my app to text.
error "invalid_grant"
To solve, I went to the test account and navigate to the activities section and click x (x) to log out and intend again.
Also applies to other oauth 2
thanks

Apple Sign In with Flutter and Auth0

I have a flutter app and use this package to implement Apple Sign In feature: https://pub.dev/packages/sign_in_with_apple
I get the authorization data from the Apple like below:
userIdentifier = "0XXXX7.6bb65XXXXXXXXXXXXXXXX36.1XXX2"
givenName = "test"
familyName = "signing"
email = "testemail#company.com"
authorizationCode = "c372xxxxxxxa526eexxxxxx1111e.0.rwsex.SwXxxXXXdDj_XxxXXXxxX"
identityToken = "eyJraXxxuxjxxxXxxxXx.eyJXxxxxtXxxxxxxhlYXxxXXxXxXXXXX"
state = null
Then I tries to send the authorizationCode as described here in Step 3: https://auth0.com/docs/connections/nativesocial/apple
And I get the 403 Forbidded {"error":"invalid_grant","error_description":"Invalid authorization code"}
I have configured the settings in the Auth0 dashobard in Social and Applications section.
The login process works well in the web environment but I can not do it in the Flutter.
Could anyone help me with what should I do with the authorizationCode to perform successful login and get Access Token and ID Token from Auth0 in the native app?
Rather a late answer, but I've found following the documentation for the /oauth/token end-point titled "Token Exchange for Native Social" works for me.
Specifically sending that end-point a POST, eg. with this in Dart code:
final appleAuthorizationCode = '???????????????????????';
const url = 'https://$AUTH0_DOMAIN/oauth/token';
final uri = Uri.parse(url);
final result = await http.post(
uri,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: {
"client_id": AUTH0_CLIENT_ID,
"grant_type": 'urn:ietf:params:oauth:grant-type:token-exchange',
"subject_token": appleAuthorizationCode,
"subject_token_type": 'http://auth0.com/oauth/token-type/apple-authz-code',
"scope": 'openid profile offline_access',
},
encoding: Encoding.getByName('utf-8'),
);
print('AUTH0 result: $result');
works for me.

Using Axios as an Alternative to request in nodejs

I am building a flutter application that requires oauth 1 authorization for one of the third party services I am using. Because flutter oauth 1 package is restricted I decided to use the oauth 1 package that npm provides. This is the code that is used to access the user generated access token from the site.
I previously used request to make a call to the api endpoint first, to access the token and secondly to use the token recieved to make another call to a different resource endpoint
How can I use axios to make the same request, emphasis on the fact that each request needs a hmac-sha1 signed signature in the header.
Thank you.
consumer: {
key: CONSUMER KEY,
secret: CONSUMER SECRET,
},
signature_method: 'HMAC-SHA1',
hash_function(base_string, key) {
return crypto
.createHmac('sha1', key)
.update(base_string)
.digest('base64')
},
})
const request_data = {
url: 'https://www.instapaper.com/api/1/oauth/access_token/',
method: 'POST',
data: { x_auth_username : USERNAME , x_auth_password : PASSWORD , x_auth_mode : 'client_auth' },
}
request(
{
url: request_data.url,
form: request_data.data,
method: request_data.method,
headers: oauth.toHeader(oauth.authorize(request_data)),
},
function(error, response, body) {
// Process your data here
console.log(error);
console.log(response);
console.log(body);
}
)
Finally found the answer for this link to the issue created on github
https://github.com/axios/axios/issues/2771

How to access params from URL after redirect to different site (Express)

The SurveyMonkey API (documentation) requires implementation of oauth to let the user decide which scopes of their account the developer has access to.
I have the following code (adapted from this question) as a means to implement the first two steps in their documentation:
app.get('/surveymonkey/oauth', function (req, res) {
const code = req.query.code;
const post_body = querystring.stringify({
"client_secret": <client_secret>,
"redirect_uri": "https://b2e3b137.ngrok.io/surveymonkey/oauth",
"grant_type": "authorization_code",
"code": code
});
const options = {
hostname: 'api.surveymonkey.net',
port: 443,
path: 'oauth/authorize?api_key=<api_key>&redirect_uri=https%3A%2F%2Fb2e3b137.ngrok.io%2Fsurveymonkey%2Foauth&response_type=code&client_id=<client_id>',
method: 'GET',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(post_body)
}
};
res.redirect('https://api.surveymonkey.net/oauth/authorize?api_key=<api_key>&redirect_uri=https%3A%2F%2Fb2e3b137.ngrok.io%2Fsurveymonkey%2Foauth&response_type=code&client_id=<client_id>');
console.log(req.params);
console.log(req.body);
console.log(req.query);
req.on('error', function(e) {
console.error(e);
});
});
When I fire up an ngrok server (ngrok http 443), everything is going fine, except when I hit the '/surveymonkey/oauth' route and validate the scopes (acting as the user), I get redirected to the route I specified in my SurveyMonkey App console, which contains the short-lived 'code' param that I'm trying to assign to the user, but I cannot get access to the 'code' param in the query string since it's been redirected to a different site.
The problem I'm currently facing looks similar to this and this, and I'm trying to get meaningful data back from req, but as you can see in the comments above, all of the data is undefined.