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
Related
I'm using loopback at work and just started new project with this framework.
When i'm refreshing token i noticed that lb4 is just generating a basic jwt token,
i digged in node modules and sees that the refreshService.refreshToken method is actually not returning the new refresh token anywhere.
so my questions are:
Does i have to generate a new refresh token manually when refreshing token ?
Does exists a better way to get the userprofile when refreshing token as i dont have a token to decode (except the new generated token)
here is the code used for refreshing token
#post('/runners/token/refresh')
#response(200, {
content: {
'application/json': {
schema: {
properties: {
access_token: {type: 'string'},
refresh_token: {type: 'string'},
expires_in: {type: 'string'}
}
}
}
}
})
async refreshToken(
#requestBody({content: {'application/json': {schema: {properties: {refresh_token: {type: 'string'}}}}}})
body: {refresh_token: string}
) {
const {
refreshToken: refresh_token,
accessToken: access_token,
expiresIn: expires_in
} = await this.refreshService.refreshToken(body.refresh_token);
return {refresh_token, access_token, expires_in};
}
also it's declared in loopback modules that the refreshToken method return a access+refresh token + expires in but that not the case...
thanks a lot
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
Version
module: 5.0.0-1624817847.21691f1
nuxt: 2.15.8
Nuxt configuration
Universal
Nuxt configuration
// Auth: https://auth.nuxtjs.org/ (v5)
auth: {
redirect: {
login: '/account/login/',
logout: '/account/login/',
callback: '/account/login/',
home: '/account/beams/'
},
strategies: {
local: {
scheme: 'refresh',
token: {
property: 'access_token',
maxAge: 120, // seconds, 2 minutes
global: true
},
refreshToken: {
property: 'refresh_token',
data: 'refresh_token',
maxAge: 1209600 // seconds, 2 weeks
},
user: {
property: 'user',
autoFetch: true
},
endpoints: {
login: { url: '/api/account/login', method: 'post', propertyName: 'token' },
refresh: { url: '/api/account/refresh', method: 'post', },
logout: { url: '/api/account/logout', method: 'post' },
user: { url: '/api/account', method: 'get' }
},
autoLogout: false
}
}
},
Additional information
Checklist
[x] I have tested with the latest Nuxt version and the issue still occurs
[x] I have tested with the latest module version and the issue still occurs
[x] I have searched the issue tracker and this issue hasn't been reported yet
Steps to reproduce
What is expected?
When a user's token expires and refresh scheme is implemented, a user shouldn't be logged out and redirected back to the login screen, the refresh token should be used to obtain a new token and the transition should be seamless allowing any authenticated route to continue to work.
What is actually happening?
In my Nuxt project with the Auth module I've implemented the refresh scheme, however, when my token expires I don't see any request in my network being made to the refresh route after my token expires and I navigate to a protected page via the auth middleware.
I expect I'm missing some simple configuration?
My current token has an expiry of 1 minute for testing, and my refresh token has an expiry of 14 days for testing.
However, when adding:
scheme: 'refresh'
refresh: { url: '/api/account/refresh', method: 'post', }
the functionality appears to not be fetching my user and automatically logging me in.
My /api/account/refresh endpoint in my API returns the following:
{
refresh_token: 'my refresh token',
token_type: 'bearer',
expired_in: 5000
}
My /api/account/login endpoint in my API returns the following:
{
access_token: 'my token',
token_type: 'bearer',
expired_in: 1000
}
What am I missing?
You need to return refresh token from /api/account/login. And then set in conf property name of it.
I have same issue with very similar comfiguration. This is my result from API (I added refresh token to the result):
{
"access_token": "XXX",
"refresh_token": "XXX",
"expired_in": 3600,
"token_type": "bearer"
}
If I inspect cookies, I can see acces token, but refresh token does not set:
I try to manually set refresh token after login, but with same result:
const result = await this.$auth.loginWith('local', {
data: this.login,
})
this.$auth.setUserToken(result.data.accessToken, result.data.refreshToken)
I'm using vue cli and I try to get album list from my google photos account.
I'm using axios-oauth-client and I try to implement this code:
const axios = require('axios');
const oauth = require('axios-oauth-client');
const getAuthorizationCode = oauth.client(axios.create(), {
url: 'https://oauth.com/2.0/token',
grant_type: 'authorization_code',
client_id: 'foo',
client_secret: 'bar',
redirect_uri: '...',
code: '...',
scope: 'baz',
});
const auth = await getAuthorizationCode(); // => { "access_token": "...", "expires_in": 900, ... }
As described in here and I can't understand how do I get the authorization code aka code in this implementation.
I managed to do this call in postman but I'm unable to do it using axios.
Postman
My Code
async function getToken() {
const getAuthorizationCode = oauth.client(axios.create(), {
url: "https://oauth2.googleapis.com/token",
grant_type: "authorization_code",
client_id:
"**********.apps.googleusercontent.com",
client_secret: "***********",
redirect_uri: "http://localhost:8080/oauth2/callback",
code: "...",
scope: "https://www.googleapis.com/auth/photoslibrary.readonly"
});
const auth = await getAuthorizationCode(); // => { "access_token": "...", "expires_in": 900, ... }
console.log(auth);
}
getToken();
What am I doing wrong?
Thanks!
UPDATE
I still didn't manage to make it works but I found this answer which I will try to check.
UPDATE#2
Eventually I ended up using google documentation for Oauth2 using php and I took their git example as a base project.
In order to do it I also needed to use database to save the tokens and especially the refresh token which I use to refresh the access token every time I receive 401.
I'm using PassportJS and passport-google-oauth in an ExpressJS web app.
var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
passport.use(new GoogleStrategy({
clientID: GOOGLE_CLIENT_ID,
clientSecret: GOOGLE_CLIENT_SECRET,
callbackURL: CALLBACK
},
function(accessToken, refreshToken, profile, done) {
console.log(profile.displayName);
console.log(profile.name.familyName);
console.log(profile.name.givenName);
...
}));
The problem is that profile.displayName, profile.name.familyName and profile.name.givenName are undefined. When I use the callback with Passport Facebook, no problem at all.
How to get the name of the user when using a Google account to login?
When I checked it seems it has more parameters than what is in the official sample leading people to confusion including me..
rather than
function(accessToken, refreshToken, profile, done)
use
function(req, accessToken, refreshToken, profile, done)
you need to request for it, include 'https://www.googleapis.com/auth/userinfo.profile' in your scope.
passport.use(new GoogleStrategy({
clientID: GOOGLE_CLIENT_ID,
clientSecret: GOOGLE_CLIENT_SECRET,
callbackURL: CALLBACK,
scope: ['https://www.googleapis.com/auth/userinfo.profile','email', ...]
}