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
Related
We have the following steps to authenticate with Office 365 and get the access tokens required to request calendar events...
Send the user to https://login.microsoftonline.com/common/oauth2/authorize?response_type=code , passing the client id and a redirect URL
The user logs in and is redirected back to the redirect URL with a ?code= query string value
Make an API request to https://login.microsoftonline.com/common/oauth2/token to get a token for the https://api.office.com/discovery/ resource, passing the code that we got in step 2
Store the access token and refresh token which is returned
Make an API request to https://api.office.com/discovery/v2.0/me/services to get a list of end points that we have access to
For the end point that I want to work with (Office 365 Exchange) , make an API request to https://login.microsoftonline.com/common/oauth2/token to get a token for the https://outlook.office365.com/ resource, passing the code that we got in step 2
Store the access token and refresh token which is returned
Use the access token from step 7 to fetch calendar events
This used to work fine, but today I'm getting a different result from the API call on step 6
I used to get an access token and refresh token which I could use for the outlook.office365.com resource, but now I'm getting an error message like the following...
{
"error":"invalid_grant",
"error_description":"AADSTS70002: Error validating credentials. AADSTS54005: OAuth2 Authorization code was already redeemed, please retry with a new valid code or use an existing refresh token.
Trace ID: 37f11c2c-6450-4040-b297-48268c6d4b00
Correlation ID: afdeb0cb-c14a-4267-9a5d-2422a1f84d62
Timestamp: 2019-01-29 22:26:24Z",
"error_codes":[70002,54005],
"timestamp":"2019-01-29 22:26:24Z",
"trace_id":"37f11c2c-6450-4040-b297-48268c6d4b00",
"correlation_id":"afdeb0cb-c14a-4267-9a5d-2422a1f84d62"
}
So it looks like I need to pass a different code the second time I make a request to get access tokens, but where do I get this different code from?
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.
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.
In the project I am currently working on, I have the following situation: there is a web application that is accessible for human users through a browser, where the user can manipulate data in a database (representing the state of household devices in a house) after he has logged in. The logging functionality is implemented with the ZfcUser module. Furthermore, the application is accessible for a computer (a raspberry pi that is installed in the house with the devices and is responsible for turning them on and off), which sees the state of the database and reacts accordingly.
The communication between the computer and the application is implemented using JSON and works fine. But right now, the computer does not send any user specific information (email, password...) so that the application functionality used by the raspberry can be accessed by any post request to the right URL. I would like to include the email and the password of the user into the JSON object sent by the computer, so that before executing a function, the web application checks whether the request is valid.
What I would like to know is whether there is a simple possibility to check whether the credentials (email and password, both represented as strings) are valid using ZfcUser (if I understand it correctly, the zfcUserAuthentification() methods can not be used for this task because they work with the cookies stored by the browser).
You can use the httprequest and populate it with credentials from JSON POST, then try to authenticate on it after calling prepareForAuthentication
$adapter = $this->zfcUserAuthentication()->getAuthAdapter();
/** #var \Zend\Http\Request */
$fakeRequest = $this->getRequest();
$fakeRequest->getPost()->set('identity', $username);
$fakeRequest->getPost()->set('credential', $password);
$result = $adapter->prepareForAuthentication($this->getRequest());
// Return early if an adapter returned a response
if ($result instanceof Response) {
throw new LoginException("");
}
$auth = $this->zfcUserAuthentication()->getAuthService()->authenticate($adapter);
if (!$auth->isValid()) {
$this->flashMessenger()->setNamespace('zfcuser-login-form')->addMessage($this->failedLoginMessage);
$adapter->resetAdapters();
// Password does not match
throw new LoginException("Invalid Username or password");
}
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();
}
}