How to use Auth0's CredentialsManager for Local Biometric Auth with React Native - react-native

The auth0 documentation on their credentials manager states
The credentials manager is an easy to use source of Keychain-based
authentication for iOS and Android, and should be usable with
auth.credentialsManager
When trying to use this suggested method
const isLoggedIn = await auth0.credentialsManager.hasValidCredentials();
This error is being thrown
undefined is not an object (evaluating '_$$_REQUIRE(_dependencyMap[10],
"../context/actions/authActions").auth0.credentialsManager.getCredentials')
Here's an overview of our auth0 configuration, and how it works currently
in AuthActions.js
export const auth0 = new Auth0({
domain: Config.AUTH0_DOMAIN,
clientId: Config.AUTH0_CLIENT_ID,
});
export const actionLogin = async (callback) => {
try {
const authState = await auth0.webAuth.authorize({
scope: 'openid profile email offline_access',
audience: Config.AUTH0_AUDIENCE,
prompt: 'login',
});
let response = await getState(authState, callback);
return response
} catch (e) {
console.log('Error Authenticating: ', e)
}
The hasValidCredentials() method mentioned above is called after a user has successfully authenticated with the webAuth, and it should be returning something along the lines of an access token, refresh token, id, and email per the docs
Note that we are trying to use this so that we can stop using the react-native-keychain package and use auth0's implementation of the native keystores by
await auth0.credentialsManager.requireLocalAuthentication();

Related

Google OAuth2 with Passport and Express

I am struggling with getting Google OAuth to work with my Express/React application whilst using Passport.js. I am using JWTs, not sessions.
In my React webapp client, I have a "login with Google" button that calls my backend API /auth/google/ with the following route setup in Express:
router.get('auth/google', passport.authenticate('google', {session: false, scope: ['email','profile']}) );
My Passport.js google strategy is:
const googleStrategy = new GoogleStrategy(
{
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: "http://localhost:3000/api/v1/auth/google/callback",
passReqToCallback : true
},
async (request, accessToken, refreshToken, profile, done) => {
try {
console.log('profile', profile);// ** CORRECT USER PRINTED **
let existingUser = await User.findOne({ 'google.id': profile.id });
// if user exists return the user
if (existingUser) {
console.log('Found existing user...');
return done(null, existingUser);
}
// if user does not exist create a new user
const newUser = new User({
method: 'google',
googleId: profile.id,
profileImage: profile.photos[0].value,
firstName: profile.name.givenName,
lastName: profile.name.familyName,
shortName: profile.displayName,
});
await newUser.save();
return done(null, newUser);
} catch (error) {
return done(error, false)
}
}
);
My Google developer dashboard is setup to call the following URL in my Express API backend upon successful authentication: /auth/google/callback
My Express route for this is defined as: router.get('auth/google/callback', passport.authenticate('google', {session: false}), authController.googleAuthCallback);
My Express googleAuthCallback function is defined as:
exports.googleAuthCallback = async (req, res) => {
console.log(req.user) // ** WRONG USER PRINTED HERE ** different from above user printed in google strategy
}
The strange this is when I console.log the profile variable in my googleStrategy, I get the right user profile information for the account from Google. This means the authentication vis a vis Google is fine. However, this same account is NOT being provided to my /auth/google/callback endpoint in the req.user object at that location. It is an entirely different account (it is the first value from my database of Users, which is authenticated using local authentication).
How do I get the user object back to my Express callback endpoint that I supplied to Google in the developer console as the authorized redirect URI?
As a general question, what happens after the strategy calls return done(null, existingUser);? I have no callback in the /auth/google route after the passport.authenticate() middleware is called so what happens next?
I am using "passport-google-oauth20": "^2.0.0"
My let existingUser = await User.findOne({ 'google.id': profile.id });
line was incorrect and was essentially returning no user. Mongoose does not complain and hence the strategy was just returning the first user from my database rather than the authenticated google user.

OctoKit with Auth0 (Github Login) in NextJS

I am building a Next JS app that has Github Login through Auth0 and uses the Octokit to fetch user info / repos.
In order to get the IDP I had to setup a management api in auth0. https://community.auth0.com/t/can-i-get-the-github-access-token/47237 which I have setup in my NodeJs server to hide the management api token as : GET /getaccesstoken endpoint
On the client side : /chooserepo page, I have the following code :
const chooserepo = (props) => {
const octokit = new Octokit({
auth: props.accessToken,
});
async function run() {
const res = await octokit.request("GET /user");
console.log("authenticated as ", res.data);
}
run();
And
export const getServerSideProps = withPageAuthRequired({
async getServerSideProps({ req, params }) {
let { user } = getSession(req);
console.log("user from get session ", user);
let url = "http://localhost:4000/getaccesstoken/" + user.sub;
let data = await fetch(url);
let resData = await data.text();
return {
props: { accessToken: resData }, // will be passed to the page component as props
};
},
});
However, I keep getting Bad credentials error. If I directly put the access token in the Octokit it seems to work well, but doesn't work when it's fetching the access token from the server.
It seems like Octokit instance is created before server side props are sent. How do I fix it ?
I figured out the error by comparing the difference between the request headers when hardcoding and fetching access token from server. Turns out quotes and backslashes need to be replaced (and aren't visible when just console logging)

React native firebase google login access Token returns Undefined

My app has a Firebase based Google login. I am trying to get access Token but getting undefined.I am getting the idToken but I need AccessToken and refresh Tokens.I need help
Here is my code :
GoogleSignin.configure({
scopes: ['profile', 'email','https://www.googleapis.com/auth/calendar'], //adding calender scope
webClientId: '863338747777-9bshdpj951ga8nik9tbtua52ji0h06k4.apps.googleusercontent.com',
offlineAccess: true,
forceCodeForRefreshToken: true,
});
const onGoogleButtonPress = async()=> {
try
{
await GoogleSignin.hasPlayServices();
const {accessToken, idToken} = await GoogleSignin.signIn();
const credential = auth.GoogleAuthProvider.credential(
idToken,
accessToken,
);
await auth().signInWithCredential(credential);
console.log('IDToken: ',idToken,accessToken)
console.log('AccessToken: ',accessToken)
}
catch(error)
{
console.log(error)
}
finally{
setLoggedIn(true)
}
}`
I found a solution for my own problem. I am using a older library of React native google sign in. The new one is react native login google. The new package is returning the accessToken as well. So to get the refresh token we need to use a api
This is the Link for that .
We need several headers
Take a look at them
You will get the serverAuthCode from the googleSignin function while signing in .
const UserInfo = await GoogleSignin.signIn();
Console log the UserInfo to get the serverAuthCode ,AccessToken and Refresh Token
This is the Package I am using for googlesignIn
Prabhakar I hope this link helpful for him.
https://www.freecodecamp.org/news/google-login-with-react-native-and-firebase/
Thank You

How to pass an Amplify Cognito session from react native to webview?

I have a react native app that renders a WebView of a Web app
The react native app uses Cognito and Amplify for authentication.
The web app also uses the same Cognito and Amplify for authentication.
I have a login flow built with in the react native that has email/password login and social media federated Oauth logins. Both these login flows successfully work in the react native space and return a
CognitoUserSession {
idToken: CognitoIdToken,
refreshToken: CognitoRefreshToken,
accessToken: CognitoAccessToken,
clockDrift: 0
}
When the react native app renders the WebView the web app is unauthenticated. I am able to pass the CognitoUserSession data into the WebView successfully. Unfortunately, I don't see a way to have Amplify re-authenticate with this session.
this is the mobileLogin function I wrote that works
import Amplify, { Auth } from 'aws-amplify';
import {
CognitoUser,
CognitoUserSession,
CognitoIdToken,
CognitoRefreshToken,
CognitoAccessToken,
} from 'amazon-cognito-identity-js';
window.mobileLogin = async function(mobileSession) {
amplify = Amplify.configure({
...config().amplify,
userPoolWebClientId: '', //switch to mobile client
});
const localSession = new CognitoUserSession({
IdToken: new CognitoIdToken({ IdToken: mobileSession.idToken.jwtToken }),
RefreshToken: new CognitoRefreshToken({ RefreshToken: mobileSession.refreshToken }),
AccessToken: new CognitoAccessToken({ AccessToken: mobileSession.accessToken.jwtToken }),
});
const localUser = new CognitoUser({
Username: mobileSession.accessToken.payload.username,
Pool: Auth.userPool,
Storage: Auth.userPool.storage,
});
localUser.setSignInUserSession(localSession);
// this seems like a hack
Auth.currentCredentials = async () => localSession;
try {
await Auth.currentSession();
console.warn(`mobile login current session!!`);
store.dispatch(silentReloginAction())
} catch (ex) {
console.warn(`mobile login ${ex}`);
}
};
}
For someone who still need this.
First, you need add oauth setting to your Web application's AwsExports.json.
const AwsExports = {
Auth: {
...
oauth: {
domain: 'xxx.auth.us-east-1.amazoncognito.com',
scope:['openid'],
redirectSignIn: 'https://example.com',
redirectSignOut: 'https://example.com',
responseType: 'token'
}
},
};
then you can pass token with uri.
const session = await Auth.currentSession(),
id_token = session.getIdToken().getJwtToken(),
access_token = session.getAccessToken().getJwtToken(),
uri = `https://example.com##id_token=${id_token}&access_token=${access_token}`;
You should actually setup oauth things.
Because webview is opened as part of Oauth flow, oauth loggin out flow can be executed.
so without proper setting of oauth, error comes up

How to properly authenticate and use GoogleCalendar-API using oAuth2 in Vue CLI environment

I'm trying to integrate Google-Calendar-API in my Vue-CLI-based Webapp. I have decided to use the node.js version of GoogleAPI as learned from this site: https://developers.google.com/calendar/quickstart/nodejs#troubleshooting. However, I got:
TypeError: Expected input to be a Function or Object, got
undefined
This is for my personal project written in Vue-Cli, Vue Router, Vuetify.js, and additionally authenticated through Firebase (login via Google account). After a user logs in through Firebase UI (via Google account), they will get access to the dashboard page where they shall be able to access their calendar via Google's oAuth2 API system (stuck). I have initially tried using the browser-based javascript API but failed (and personally preferred node.js version later).
Dashboard.vue
<script>
import { config } from "#/../hidden/config.js";
const {google} = require('googleapis');
// If modifying these scopes, delete token.json.
// The file token.json stores the user's access and refresh tokens, and is
// created automatically when the authorization flow completes for the first
// time.
const TOKEN_PATH = '#/assets/token.json';
export default {
data() {
return {
oAuth2Client: null,
SCOPES: ['https://www.googleapis.com/auth/calendar.readonly'],
client_secret: "",
client_id: "",
redirect_uris: ""
};
},
methods: {
/**
* Create an OAuth2 client with the given credentials, and then execute the
* given callback function.
* #param {Object} credentials The authorization client credentials.
* #param {function} callback The callback to call with the authorized client.
*/
authorize: () => {
const self = this;
self.oAuth2Client = new google.auth.OAuth2(
client_id, client_secret, redirect_uris[0]);
self.getAccessToken(self.oAuth2Client);
self.oAuth2Client.setCredentials();
self.listEvents(oAuth2Client);
},
/**
* Get and store new token after prompting for user authorization, and then
* execute the given callback with the authorized OAuth2 client.
* #param {google.auth.OAuth2} oAuth2Client The OAuth2 client to get token for.
* #param {getEventsCallback} callback The callback for the authorized client.
*/
getAccessToken: () => {
const self = this;
const authUrl = self.oAuth2Client.generateAuthUrl({
access_type: 'offline',
scope: SCOPES,
});
console.log('Authorize this app by visiting this url:', authUrl);
self.oAuth2Client.getToken(code, (err, token) => {
if (err) return console.error('Error retrieving access token', err);
self.oAuth2Client.setCredentials(token);
// self.listEvents();
});
}
/**
* Lists the next 10 events on the user's primary calendar.
* #param {google.auth.OAuth2} auth An authorized OAuth2 client.
*/
/*
listEvents: () => {
const self = this;
const auth = self.oAuth2Client;
const calendar = google.calendar({version: 'v3', auth});
calendar.events.list({
calendarId: 'primary',
timeMin: (new Date()).toISOString(),
maxResults: 10,
singleEvents: true,
orderBy: 'startTime',
}, (err, res) => {
if (err) return console.log('The API returned an error: ' + err);
const events = res.data.items;
if (events.length) {
console.log('Upcoming 10 events:');
events.map((event, i) => {
const start = event.start.dateTime || event.start.date;
console.log(`${start} - ${event.summary}`);
});
} else {
console.log('No upcoming events found.');
}
});
}
*/
},
created: function() {
const {credentials} = require("#/credentials.json");
this.client_secret = credentials.installed.client_secret;
this.client_id = credentials.installed.client_id;
this.redirect_uris = credentials.installed.redirect_uris;
//this.authorize();
}
};
</script>
I expect to be able to connect to the Google Calendar API and start working on actually manipulating the calendar event info for my purpose. However, I'm getting the error:
TypeError: Expected input to be a Function or Object, got
undefined
.
I have tried looking for people with similar problems online, however I didn't find any video guides or written guides for Vue-cli projects that use Google APIs.
I do confess that I have modified my code a little bit from the referenced sample from the website to avoid using fs and readline npm packages. However, the error message was same in those cases too.