expo oauth2 google refresh token - react-native

I am trying to implement oauth2 with google in expo and I wanted to receive the refresh token, however, google is not emitting the refresh token only a access token.
Already tried this Refresh token with expo auth sessions (Google) but it did not work for me.
const [request, response, promptAsync] = Google.useAuthRequest({
expoClientId: GOOGLE_CLIENT_ID,
responseType: "code",
shouldAutoExchangeCode: false,
extraParams: {
access_type: "offline"
},
});

Related

Cannot authenticate with Twitter using Expo

I am trying to use OAuth2 to authenticate with Twitter on my React-Native/Expo app, using the expo-auth-session package (Expo's guide for Twitter OAuth).
The Twitter OAuth2 flow works in two steps : first the user authorizes the app to access their account, which returns a code, then we exchange that code for an access token.
I am stuck at the second step.
Whenever I try to exchange the code for a token, using expo's exchangeCodeAsync function with these parameters :
exchangeCodeAsync({
clientId: '<CLIENT_ID>',
redirectUri: makeRedirectUri({
scheme: 'my.app',
useProxy
}),
code: response.params.code,
extraParams: {
client_id: "<CLIENT_ID>",
code_verifier: request?.codeVerifier || '',
redirect_uri: makeRedirectUri({
scheme: 'my.app',
useProxy
}),
grant_type: "authorization_code",
},
}, discovery)
I get this error :
Possible Unhandled Promise Rejection (id: 0):
SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON
What I understand is that the function makes a request to the /oauth2/token route of the Twitter API under the hood, but because of some wrong parameter it returns an HTML error code :
Something went wrong, but don’t fret — let’s give it another shot.
Since the error message is so vague, I have no idea of what is wrong with my request.
I assume that since I have completed the authorization step, the redirect_uri is properly configured. I have also made sure that the format for the "code_verifier" and "code" fields were valid, according to Twitter's documentation.
Here is an Expo Snack to show the complete App.js setup I am using (I've also configured app.json with a custom scheme )
https://snack.expo.dev/lWYp82Pwq
I was able to get a working Twitter login using a bit of a cobbled-together code path:
const twitterDiscovery = {
authorizationEndpoint: "https://twitter.com/i/oauth2/authorize",
tokenEndpoint: "https://api.twitter.com/2/oauth2/token",
}
...
const redirectUri = AuthSession.makeRedirectUri({
scheme: APP_URI_SCHEME,
useProxy: true,
})
const reqConfig = {
clientId: TWITTER_CLIENT_ID,
redirectUri,
usePKCE: true,
scopes: twitterScopes,
}
const authReq = new AuthRequest(reqConfig)
const authUrl = await authReq.makeAuthUrlAsync(twitterDiscovery)
const loginResult = await AuthSession.startAsync({ authUrl, returnUrl })
if (loginResult.type !== "success") {
throw new Error("...")
}
const tokenRequest = new AccessTokenRequest({
...reqConfig,
code: loginResult.params.code,
extraParams: {
code_verifier: authReq.codeVerifier,
},
})
const tokenResult = await tokenRequest.performAsync(twitterDiscovery)
This could obviously be cleaned up a bit, but it does appear to be functional, so I wanted to post even though it's not pretty.

Refresh token with expo auth sessions (Google)

I use for my Android app expo-auth-sessions to authorize the user via Google:
const [request, response, promptAssync] = Google.useAuthRequest({
androidClientId: ANDROID_CLIENT_ID,
iosClientId: IOS_CLIENT_ID,
expoClientId: EXPO_CLIENT_ID,
scopes: [
"https://www.googleapis.com/auth/drive",
],
})
The request works just fine and it returns an access token, but it does not contain a refresh token.
Is there any possibility to configure the request that it also returns a refresh token or something similar to not force the user to sign in again after the access token expires?
Current response:
{
authentication: {
accessToken: TOKEN,
expiresIn: "3599",
idToken: undefined,
issuedAt: 1644693943,
refreshToken: undefined,
scope:
"https://www.googleapis.com/auth/drive",
tokenType: "Bearer",
},
params: {
access_token: TOKEN,
expires_in: "3599",
scope:
"https://www.googleapis.com/auth/drive",
token_type: "Bearer",
},
type: "success"
}
Thanks in advance!
You'll have to add access_type: "offline" (Google APIs auth) in your auth URL because expo doesn't do that by default. For this, you can make use of the extraParams attribute in useAuthSession. However, access_type: "offline" is not supported for responseType: "token" (the default value) since the concept of refresh_token doesn't exist for implicit_grant_flow. You'll have to change that to responseType: "code" and later exchange the obtained code for access and refresh token on the server side. Overall you'll have to make the following changes -
const [request, response, promptAssync] = Google.useAuthRequest({
androidClientId: ANDROID_CLIENT_ID,
iosClientId: IOS_CLIENT_ID,
expoClientId: EXPO_CLIENT_ID,
scopes: [
"https://www.googleapis.com/auth/drive",
],
responseType: "code",
shouldAutoExchangeCode: false,
extraParams: {
access_type: "offline"
},
})
However, if you've already authorized the app once before, you might have to add prompt: 'consent' too. You can take a look at this answer for more clarity - https://github.com/googleapis/google-api-python-client/issues/213#issuecomment-205886341

Microsoft Azure login success returns empty scopes - react-native-app-auth - Getting 401

While I try to make an custome backend API call with the accessToken I receive from login success using react-native-app-auth, the call fails and returns a 401 error.
My login succeeds with no error but the response I get after login, consists of empty scopes scopes: []
Below is my config,
const AuthorizationConfig = {
appId: 'XXXXX',
tenantId: 'XXXX',
appScopes: [
'openid',
'offline_access',
'profile',
'User.Read',
'api://XXXX/access_as_user',
],
};
export const config: any = {
warmAndPrefetchChrome: true,
clientId: AuthorizationConfig.appId,
redirectUrl: 'com.dcomobile://react-native-auth/',
scopes: AuthorizationConfig.appScopes,
additionalParameters: {prompt: 'select_account'},
serviceConfiguration: {
authorizationEndpoint:
'https://login.microsoftonline.com/' +
AuthorizationConfig.tenantId +
'/oauth2/v2.0/authorize',
tokenEndpoint:
'https://login.microsoftonline.com/' +
AuthorizationConfig.tenantId +
'/oauth2/v2.0/token',
},
};
I call this function to authorize which in turn opens a Microsoft Login window in a mobile browser
const result = await authorize(config);
result.accessToken contains the token which I have to append to the header section in my API call. The token is a Bearer token
I'm wondering if my scopes are wrong as it as scopes for both MSGraph and custom API.
Any leads would be helpful! TIA

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