I have the authentication process working great with TweetSharp to log my users into my app. I then fetch and save the oauth_token and oauth_token_verifier on my system.
I have tried to use that same token/verifier combo to log the user back in which does prevent the necessity to have the user authorize the app again...however, I've noticed when I log in to twitter on the web, that token/verifier combination no longer is valid and so trying to log them in again doesn't work.
I dont' mind requesting a new token/verifier combo every time, but I dont' want to force my users to have to authorize the app every time. Is there a way around this?
here is the relevant code from my twitterloginhelper class:
LocalUser lsuser = new LocalUser();
TwitterService service = new TwitterService(consumer_key, consumer_secret);
OAuthAccessToken accessToken = service.GetAccessToken(requestToken, oauth_verifier);
service.AuthenticateWith(accessToken.Token, accessToken.TokenSecret);
TwitterUser user = service.VerifyCredentials(new VerifyCredentialsOptions());
lsuser.oauth_token = oauth_token;
lsuser.oauth_token_secret = oauth_verifier;
lsuser.profile_pic = user.ProfileImageUrl;
lsuser.login_type = "Twitter";
lsuser.username = user.Name;
lsuser.oauth_uid = user.Id.ToString();
lsuser.email = "";
return lsuser;
}
got this figured out.
once you have the requestToken, instead of calling TwitterService.GetAuthorizationUrl, call TwitterService.GetAuthenticationUrl.
that will make it authorize the app only once, and each subsequent time, allow the user to just log in w/o re-authorizing.
Related
I'm using the Google Identity Platform's OAuth 2.0 flow to authorize a javascript/HTML teacher observation form to write to a Google Sheets document. Everything is working well most of the time; however, last night one of our principals hit the following error:
"Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project."
I determined that he had launched the observation tool in the afternoon, and now maybe five hours later was trying to click the submit button. My hunch was that the token had expired, but from Google's documentation it seems like the JS auth library is meant to handle refreshing the access token as necessary - I believe it's not actually possible to get a refresh token to do anything manually.
I'm using what is essentially the sample auth code, and the app responds to being signed out appropriately. That is, if I sign out in another tab, the submit button is disabled and the sign-in button appears again. Assuming token expiration is the issue here, any ideas on the correct way to identify if the token has expired and how to request a new one, ideally without user interaction? Or if it's not an expiration issue, what else could it be? This user has successfully submitted data in earlier observations; it was just this one time when he waited ~5 hours (potentially losing internet connectivity / sleeping his laptop) during that time.
Here's the auth code:
var clientId = ""; //id removed
var discoveryDocs = ["https://sheets.googleapis.com/$discovery/rest?version=v4"];
var scopes = "https://www.googleapis.com/auth/spreadsheets";
var authorizeButton = document.getElementById('authorize-button');
function handleClientLoad() {
gapi.load('client:auth2', initClient);
}
function initClient() {
gapi.client.init({
discoveryDocs: discoveryDocs,
clientId: clientId,
scope: scopes
}).then(function () {
gapi.auth2.getAuthInstance().isSignedIn.listen(updateSigninStatus);
updateSigninStatus(gapi.auth2.getAuthInstance().isSignedIn.get());
authorizeButton.onclick = handleAuthClick;
});
}
function updateSigninStatus(isSignedIn) {
if (isSignedIn) {
authorizeButton.style.display = 'none';
document.getElementById('submit').disabled = false;
findRow(); //find the empty row once we're logged in
} else {
authorizeButton.style.display = 'block';
document.getElementById('submit').disabled = true;
}
}
function handleAuthClick(event) {
gapi.auth2.getAuthInstance().signIn();
}
Thank you!
Similar issues that i had resulted in issues from that Authorized Javascript origins.
"In the Authorized JavaScript origins field, enter the origin for your app. You can enter multiple origins to allow for your app to run on different protocols, domains, or subdomains. You cannot use wildcards. In the example below, the second URL could be a production URL." taken from https://developers.google.com/identity/sign-in/web/devconsole-project.If prompt to view task came from an email, the email origin must be verified -or- the device is used for multiple accounts, the token will not stay. If the api is being improperly used, it will allow functionality for a short period of time , then fail.
This may be useful, in the authflow, you do not have scope or id in options
/** * Initiate auth flow in response to user clicking authorize button. * *
#param {Event} event Button click event. */ function
handleAuthClick(event) {
gapi.auth.authorize( {client_id: '[#app:client_id]', scope:
["googleapis.com/auth/calendar"], immediate: false}, handleAuthResult);
return false; }
I believe How to refresh expired google sign-in logins? had the answer I needed. Since all of my API calls happen at once, I added a new Date() when the page loads, a second new Date() when the submission flow begins, and if they are more than 45min (2,700,700ms) apart, I use gapi.auth2.getAuthInstance().currentUser.get().reloadAuthResponse() to force an access token refresh, as documented at https://developers.google.com/identity/sign-in/web/reference#googleuserreloadauthresponse.
Hopefully Google will eventually update their documentation to reflect this now-necessary step when using the auth2 flow vs the older auth flow.
Time will tell if this actually solved the issue, but I'm hopeful!
I hope it helps you friend that error is because you have the wrong time, you go to date and time settings then press synchronize now.
I have two related questions and I hope someone help me because I've been stuck for 2 days
First: mobile phone failed to authenticate
Here is what I have done:
1- user signs up
2- token released
3- token saved in user's device
but then when the same user try to do API requests I get
Rooute to sign up :
$api = app('Dingo\Api\Routing\Router');
$api->version('v1', function ($api) {
$api->post('auth/signup', 'App\Api\V1\Controllers\AuthController#signup');
then I get a token , so I guess everything looks great!
then now when the same device sends a post request to laravel I get this message
"message": "Failed to authenticate because of bad credentials or an invalid authorization header."
this is the route to the post request
$api->group(['middleware'=>'api.auth'],
function ($api) {
$api->post('auth/ios', 'App\Api\V1\Controllers\AuthController#create');
Second: is my method right to save data made by a mobile phone?
Since I couldn't test this method I'd like to know if this is at least one of the right ways to receive data and save it. The reason to save it is because I will show it in a control panel.
public function create(Request $request)
{
$user = new User();
$id = Auth::id();
$user->phone = $request->input('phone');
$user->city = $request->input('city');
$user->street = $request->input('street');
$user->save();
return 'Employee record successfully created with id ' . $user->id;
}
I understand that you are authenticate users based on api token.
Here is what you could do :
set up a column called api_token in users table by adding the following migration
$table->string('api_token', 60)->unique();.This generates a random api token for every user.
send the api_token back to the user's device and save it there
Send it back with every request. Preferalbly set it up globally and send it in the request Authentication request header
Get the authenticated user like so$user= Auth::guard('api')->user();
Laravel takes care of all the authentication stuff behind the scenes.
Learn More about this here
I have created webhook project with Microsoft Graph API to monitor Office 365 inbox.
I made a UpdateSubscription action method which renews it for 3 days only as according to the documentation provide on https://graph.microsoft.io/en-us/docs/api-reference/v1.0/resources/subscription
Below is the code snippet of how I'am facilitating the HTTP request to update the subscription
AuthenticationResult authResult = await AuthHelper.GetAccessTokenAsync();
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authResult.AccessToken);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// Build the request.
string subscriptionsEndpoint = "https://graph.microsoft.com/v1.0/subscriptions/"+id;
var method = new HttpMethod("PATCH");
HttpRequestMessage request = new HttpRequestMessage(method, subscriptionsEndpoint);
//get the current time
var subscription = new Subscription
{
//Id = id,
ExpirationDateTime = DateTime.UtcNow + new TimeSpan(0, 0, 4230, 0)
};
Is there a way to auto update without the user pressing the button to 'update'?
since the authorization-headers requires AuthResult.accessToken which will require the user to sign in to Office365 account.
Please advice
An option available to you is the service or daemon approach (https://graph.microsoft.io/en-us/docs/authorization/app_only). Instead of authenticating with a logged-in user you're able to renew the subscription at the application level using a Bearer token which is in turn generated by the CLIENT_SECRET from Azure AD.
I don't think storing tokens in the database is the right approach here. My understanding is that security tokens are never appropriate for a database.
In fact, I don't quite understand the need to have the user log in at all here, unless there are parts to the program that you didn't mention. A service like the one I mentioned can monitor a mailbox without a user being there, or else if the program requires the user to be there, there really isn't an issue of lost credentials.
You can use this approach to fetch accesstoken from azure using grant_type a password. PLease find the below screenshot.
In my application, the user when installs the app, needs to fill a registration form. I need to save the access_token along with the user instance.
So, if the user is unregistered, I redirect to the signup form ie. I dont save the access_token, but at this time, the app is registered. Which means, suppose when the store admin logs back in to the app, he does not get the auth code again, but gets signed_payload.
Since, I dont want to store, unregistered users on my database, I prefer calling a api, that would grant me auth code and/or access_token.
Is there any such call I can make?
To answer your question, the access token can only be obtained at the point of the initial app install, when the user installs the app for the very first time. This is the only time that BigCommerce will send the information required to obtain the access token.
Therefore your app should always save the access_token at the point of install. Your registration page should be prompted after obtaining and saving the access token. If for some reason the user installs the app and does not complete the registration, then you should simply just check on your end if the registration was finished or not, and if it wasn't then you should display it during the app load phase as a requirement before displaying your main app dashboard.
Since you didn't specify a programming language, I'm going to illustrate one in Python.
There are two parts you mentioned, registration/access token and signed payload.
The initial callback flow would look something like this:
#app.route('/bigcommerce/callback')
def auth_callback():
# Put together params for token request
code = flask.request.args['code']
context = flask.request.args['context']
scope = flask.request.args['scope']
store_hash = context.split('/')[1]
redirect = app.config['APP_URL'] + flask.url_for('auth_callback')
# Fetch a permanent oauth token. This will throw an exception on error,
# which will get caught by our error handler above.
client = BigcommerceApi(client_id=client_id(), store_hash=store_hash)
token = client.oauth_fetch_token(client_secret(), code, context, scope, redirect)
bc_user_id = token['user']['id']
email = token['user']['email']
access_token = token['access_token']
The flow using a signed payload would look something like:
#app.route('/bigcommerce/load')
def load():
# Decode and verify payload
payload = flask.request.args['signed_payload']
user_data = BigcommerceApi.oauth_verify_payload(payload, client_secret())
if user_data is False:
return "Payload verification failed!", 401
bc_user_id = user_data['user']['id']
email = user_data['user']['email']
store_hash = user_data['store_hash']
When initially creating a user in your database, you can also denote the sign up date through a function of your code and then do a periodic cron job to check if they have a registered account with you. There's not an endpoint where we store whether they completed registration with you since that is a function of your app.
I saved the Access Token (using this method: getAccessToken ()) in my database, but now I would like to restore this value to an object.
How can I do this?
This is explained in hybridauth user manual with below code :
// get the stored hybridauth data from your storage system
$hybridauth_session_data = get_sorted_hybridauth_session( $current_user_id );
Get_sorted_hybridauth_session is your internal function to get the stored data.
It doesnt matter whether you store the data in a table in a field named 'external_token' or something, get it through a normal sql query, and then just feed it to below function :
// then call Hybrid_Auth::restoreSessionData() to get stored data
$hybridauth->restoreSessionData( $hybridauth_session_data );
// call back an instance of Twitter adapter
$twitter = $hybridauth->getAdapter( "Twitter" );
// regrab te user profile
$user_profile = $twitter->getUserProfile();
$hybridauth->restoreSessionData( $hybridauth_session_data ); will restore the serialized session object, and then it will get an adapter for whichever provider it was saved for. Its best that you also save the provider name (Twitter in this case) in the same database table with something like external_provider , and then you can get it through a sql auery and feed it to getAdapter function. That should do what you need to do.
The manual example is below :
http://hybridauth.sourceforge.net/userguide/HybridAuth_Sessions.html
=============
As an added info - what i saw in my tests was, saving session in this way does not prevent hybridauth from logging the user in, even if the user has revoked access from the app in the meantime. Ie, if user is already logged in and authorized, but, went to the app separately and revoked the access (google for example), hybridauth will still log in the user to your system. Im currently trying to find a way to make sure the user is logged to the remote system too.
Late, but I thought this would help:
The following code verifies and removes those providers from HybridAuth that the user is not truly logged into:
$providers = $this->hybridauthlib->getConnectedProviders();
foreach( $providers as $connectedWith ){
$p = $this->hybridauthlib->getAdapter( $connectedWith );
try {
$p->getUserProfile();
} catch (Exception $e) {
$p->logout();
}
}