How to prevent waves Signer automatic logout if the user refreshes the page? - wavesplatform

I am following the Vladimir Zhuravlev "Getting Started with Waves Signer" example, I find to use Signer in my app, everything is going awesome, my problem is when after made an authorization and if the user refreshes the page it automatic logout, I want to prevent logout when refresh, it just must to do when the user clicks on logout.
User Authorisation
Waves Signer can be used to get the public data of an active user account from Waves.Exchange client.
The code:
try {
const userData = await waves.login(); // calling Waves Signer
event.target.classList.add("clicked");
event.target.innerHTML = `
authorized as <br>
${userData.address}`; // getting account address
} catch (e) {
console.error('login rejected') // handling user auth reject
}
});

Thank you for the question. Waves Signer is designed to operate with the user private data in a safe way. The login data is stored as a variable, this is why it's not available after reloading page. Unfortunately, there is no way to prevent logout when leaving the page.

Related

Keycloak : implement "reset password" (as admin) flow same as "forgot password" (as user)

I would like to implement this authentication flow in Keycloak:
A user creates an account by typing only his email
The user is logged in and can access my service
2'. At the same time, an email is sent to him, allowing him to "finalize" his account
The user leaves his session -> to reuse my service, he must click in the received email
By clicking in the received email, the user defines his first password
The user is then logged in automatically (without going through a login page).
The objective of this flow is to be the simplest, to hook users who are not used to webapps.
The implementation I would do:
Create an account without password request: I customize the Keycloak Registration flow by disabling the Password Validation and Profile Validation rules
Programmatically, in my webapp, at the first connection of a user, via the REST Admin API, I trigger the email action UPDATE_PASSWORD
I get something that works, but:
A. The link received by email redirects to an intermediary page confirming the execution of actions ("Perform the following action (s)") - (similar to Keycloak Implement Reset password flow same as forgot password flow)
B. The user is then redirected to a login page, and not directly connected to the application.
When, as a normal user, I trigger a reset password request (through 'forget password' feature), the process is the one I want: by clicking on the email link, I go directly to the page allowing me to enter and confirm a new password, then I'm authenticated.
My question: Do you see a way to implement this 'simplified' flow?
My keycloak version : 11.0.2
Thank you !
I could remove the "info.ftl" page display, customizing the "ExecuteActionsActionTokenHandler", as explained here :
action-token-spi
You have to create a file :
src/main/resources/META-INF/services/org.keycloak.authentication.actiontoken.ActionTokenHandlerFactory
containing the name of the class you want to use instead :
com.example.ExecuteActionTokenHandlerFactory
Then you create that class com.example.ExecuteActionTokenHandlerFactory with the following code :
public class ExecuteActionTokenHandlerFactory extends ExecuteActionsActionTokenHandler {
#Override
public Response handleToken(ExecuteActionsActionToken token, ActionTokenContext<ExecuteActionsActionToken> tokenContext) {
AuthenticationSessionModel authSession = tokenContext.getAuthenticationSession();
String redirectUri = RedirectUtils.verifyRedirectUri(tokenContext.getUriInfo(), token.getRedirectUri(),
tokenContext.getRealm(), authSession.getClient());
if (redirectUri != null) {
authSession.setAuthNote(AuthenticationManager.SET_REDIRECT_URI_AFTER_REQUIRED_ACTIONS, "true");
authSession.setRedirectUri(redirectUri);
authSession.setClientNote(OIDCLoginProtocol.REDIRECT_URI_PARAM, redirectUri);
}
token.getRequiredActions().stream().forEach(authSession::addRequiredAction);
UserModel user = tokenContext.getAuthenticationSession().getAuthenticatedUser();
// verify user email as we know it is valid as this entry point would never have gotten here.
user.setEmailVerified(true);
String nextAction = AuthenticationManager.nextRequiredAction(tokenContext.getSession(), authSession, tokenContext.getClientConnection(), tokenContext.getRequest(), tokenContext.getUriInfo(), tokenContext.getEvent());
return AuthenticationManager.redirectToRequiredActions(tokenContext.getSession(), tokenContext.getRealm(), authSession, tokenContext.getUriInfo(), nextAction);
}
}
Actually it is the same implementation as the upper class, except we removed the following part :
if (tokenContext.isAuthenticationSessionFresh()) {
...
}
which means that if the user did not have a session, which happens when the user is reseting his password, he is redirected to that "info.ftl" page.
As a workaround for problem A, I customize info.ftl template page. I add an ugly inline script to click on the link, redirecting automatically to the update password page.
<#import "template.ftl" as layout>
(...)
<#elseif actionUri?has_content>
<p><a id="yolo" href="${actionUri}">${kcSanitize(msg("proceedWithAction"))?no_esc}</a></p>
<script>document.getElementById('yolo').click()</script>
(...)
It'll do the job until I found a cleaner solution.
At the moment, B problem remains.

Swift2 Firebase: Is the email check done on the backend server? [duplicate]

Question says it all. In Firebase, how do I confirm email when a user creates an account, or, for that matter, do password reset via email.
I could ask more broadly: is there any way to send emails out from Firebase? E.g. notifications, etc. This isn't the kind of thing you would usually do client-side.
Update
Note that this was never a very secure way of handling email verification, and since Firebase now supports email verification, it should probably be used instead.
Original answer
I solved the email verification using the password reset feature.
On account creation I give the user a temporary (randomly generated) password. I then trigger a password reset which will send an email to the user with a link. The link will allow the user to set a new password.
To generate a random password you can use code similar to this:
function () {
var possibleChars = ['abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!?_-'];
var password = '';
for(var i = 0; i < 16; i += 1) {
password += possibleChars[Math.floor(Math.random() * possibleChars.length)];
}
return password;
}
Note that this is happening on the client, so a malicious user could tamper with your logic.
This would need to be done outside of firebase. I store users at /users/ and keep a status on them (PENDING, ACTIVE, DELETED). I have a small service that monitors users of a PENDING status and sends out a confirmation email. Which has a link to a webservice I've created to update the user status to ACTIVE.
[Engineer at Firebase - Update 2014-01-27]
Firebase Simple Login now supports password resets for email / password authentication.
Each of the Simple Login client libraries has been given a new method for generating password reset emails for the specified email address - sendPasswordResetEmail() on the Web and Android, and sendPasswordResetForEmail() on iOS.
This e-mail will contain a temporary token that the user may use to log into their account and update their credentials. This token will expire after 24 hours or when the user changes their password, whichever occurs first.
Also note that Firebase Simple Login enables full configuration of the email template as well as the sending address (including whitelabel email from your domain for paid accounts).
To get access to this feature, you'll need to update your client library to a version of v1.2.0 or greater. To grab the latest version, check out https://www.firebase.com/docs/downloads.html.
Also, check out https://www.firebase.com/docs/security/simple-login-email-password.html for the latest Firebase Simple Login - Web Client docs.
As at 2016 July, you might not have to use the reset link etc. Just use the sendEmailVerification() and applyActionCode functions:
In short, below is basically how you'll approach this, in AngularJS:
// thecontroller.js
$scope.sendVerifyEmail = function() {
console.log('Email sent, whaaaaam!');
currentAuth.sendEmailVerification();
}
// where currentAuth came from something like this:
// routerconfig
....
templateUrl: 'bla.html',
resolve: {
currentAuth:['Auth', function(Auth) {
return Auth.$requireSignIn() // this throws an AUTH_REQUIRED broadcast
}]
}
...
// intercept the broadcast like so if you want:
....
$rootScope.$on("$stateChangeError", function(event, toState, toParams, fromState, fromParams, error) {
if (error === "AUTH_REQUIRED") {
$state.go('login', { toWhere: toState });
}
});
....
// So user receives the email. How do you process the `oobCode` that returns?
// You may do something like this:
// catch the url with its mode and oobCode
.state('emailVerify', {
url: '/verify-email?mode&oobCode',
templateUrl: 'auth/verify-email.html',
controller: 'emailVerifyController',
resolve: {
currentAuth:['Auth', function(Auth) {
return Auth.$requireSignIn()
}]
}
})
// Then digest like so where each term is what they sound like:
.controller('emailVerifyController', ['$scope', '$stateParams', 'currentAuth', 'DatabaseRef',
function($scope, $stateParams, currentAuth, DatabaseRef) {
console.log(currentAuth);
$scope.doVerify = function() {
firebase.auth()
.applyActionCode($stateParams.oobCode)
.then(function(data) {
// change emailVerified for logged in User
console.log('Verification happened');
})
.catch(function(error) {
$scope.error = error.message;
console.log(error.message, error.reason)
})
};
}
])
And ooh, with the above approach, I do not think there's any need keeping the verification of your user's email in your user data area. The applyActionCode changes the emailVerified to true from false.
Email verification is important when users sign in with the local account. However, for many social authentications, the incoming emailVerified will be true already.
Explained more in the article Email Verification with Firebase 3.0 SDK
What I did to work around this was use Zapier which has a built in API for firebase. It checks a location for added child elements. Then it takes the mail address and a verification url from the data of new nodes and sends them forwards. The url points back to my angular app, which sets the user email as verified.
As I host my app files in firebase, I don't need have to take care of any servers or processes doing polling in the background.
There is a delay, but as I don't block users before verifying mails it's ok. Zapier has a free tier and since I don't have much traffic it's a decent workaround for time being.
The new Firebase SDK v3 appears to support email address verification, see here (put your own project id in the link) but it doesn't appear to be documented yet.
I have asked the question on SO here
See #SamQuayle's answer there with this link to the official docs.
As noted by various others Firebase does now support account related emails but even better, as of 10 days ago or so it also supports sending any kind of email via Firebase Functions. Lots of details in the docs and example code here.
I used following code to check the email verification after creating new account.
let firAuth = FIRAuth.auth()
firAuth?.addAuthStateDidChangeListener { auth, user in
if let loggedUser = user {
if loggedUser.emailVerified == false {
loggedUser.sendEmailVerificationWithCompletion({ (error) in
print("error:\(error)")
})
}
else {
print(loggedUser.email)
}
} else {
// No user is signed in.
print("No user is signed in.")
}
}
I used MandrillApp. You can create an API key that only allows sending of a template. This way even thought your key is exposed it can't really be abused unless someone wants to fire off tonnes of welcome emails for you.
That was a hack to get myself off the ground. I'm now enabling CORS from a EC2 that uses the token to verify that the user exists before extending them a welcome via SES.

GWT: A way to cancel PlaceChangeEvent?

I'm using Activity/Place in my GWT project, if current user is not logged in, when he navigates to some Place, the user will be redirect to login page, if the user has logged in, then he will be taken to that Place. How to implement this logic efficiently?
I tried to hook PlaceChangeRequestEvent:
eventBus.addHandler(PlaceChangeRequestEvent.TYPE,new PlaceChangeRequestEvent.Handler() {
#Override
public void onPlaceChangeRequest(PlaceChangeRequestEvent event) {
Place newPlace = event.getNewPlace();
if (newPlace instanceof MyProtectedPlace && userNotLoggedIn()) {
event.goTo(new LoginPlace());
}
}
});
Unfortunately it does not work since the ongoing request for MyProtectedPlace is not cancelled.
Yes I could check this when user are about to navigation away from current place, but this will not be efficient as the check logic will scattered throughout the program.
Thanks.
You can do it a little bit differently I think. Let's say that you want a place called SecuredPlace to be accessible only after login. You have a corresponding SecuredActivity.
What you can do is, when you start your SecuredActivity, you check if your user is logged in. If not you do placeController.goTo(new LoginPlace ()).
If the user is logged in then you continue. As the start is called by the framework there is no way to skip this step which in my opinion makes it secured enough.
But you should implement your security on network calls to your backend not on places. Every time you call the backend, you check that user is authenticated and has the right credentials. If not you can intercept the callback, check that it is a 403 error and then redirect automatically to your login page. Because if your backend calls are not secured, securing your places is useless.

Redirect after user has logged in

I'm pretty new to Angular, and right now I'm just trying to get all my routes set up and working as I'd like.
Setup:
When a user navigates to certain pages (/settings for this example) the app should check if there is a user already logged in. If there is continue as usual. Otherwise the user should go to the login page (/login).
What I'd like:
After the user has successfully logged in they should go to the page they were originally trying to get to (/settings)
My question:
Is there an "Angular way" to remember where the user was trying to go to?
Relevant code:
app.js
.when('/settings', {
templateUrl: '/views/auth/settings.html',
controller: 'SettingsCtrl',
resolve: {
currentUser: function($q, $location, Auth) {
var deferred = $q.defer();
var noUser = function() {
//remember where the user was trying to go
$location.path("/login")
};
Auth.checkLogin(function() {
if (Auth.currentUser()) {
deferred.resolve(Auth.currentUser());
} else {
deferred.reject(noUser());
}
});
return deferred.promise;
}
}
})
login.js
$scope.submit = function() {
if(!$scope.logInForm.$invalid) {
Auth.login($scope.login, $scope.password, $scope.remember_me)
//go to the page the user was trying to get to
}
};
Much thanks to John Lindquist for the video which got me this far.
First off, you do not want to redirect the user to a login page.
An ideal flow in a single page web app is as follows:
A user visits a web site. The web site replies with the static assets for the
angular app at the specific route (e.g. /profile/edit).
The controller (for the given route) makes a call to an API using $http, $route, or other mechanism (e.g. to pre-fill the Edit Profile form with details from the logged in user's account via a GET to /api/v1/users/profile)
If/while the client receives a 401 from the API, show a modal to
login, and replay the API call.
The API call succeeds (in this case, the user can view a pre-filled Edit Profile form for their account.)
How can you do #3? The answer is $http Response Interceptors.
For purposes of global error handling, authentication or any kind of
synchronous or asynchronous preprocessing of received responses, it is
desirable to be able to intercept responses for http requests before
they are handed over to the application code that initiated these
requests. The response interceptors leverage the promise apis to
fulfil this need for both synchronous and asynchronous preprocessing.
http://docs.angularjs.org/api/ng.$http
Now that we know what the ideal user experience should be, how do we do it?
There is an example here: http://witoldsz.github.com/angular-http-auth/
The example is based on this article:
http://www.espeo.pl/2012/02/26/authentication-in-angularjs-application
Good luck and happy Angularing!

Graph Request Only Works With My Facebook Account

I have a web page which asks the user to log in and then proceeds to get JSon via Graph for a particular Facebook group. It builds the Uri dynamically by taking the access_token that is returned after login. It works fine when I do this, but if I try to log in with a different account, no data for the feed is returned.
One hint in this problem is when the facebook dialog screen appears, it only asks for my username/password. It doesn't ask go to the usual screen where Facebook asks for you to give permissions for "Basic Information" etc. It's just a username/password screen and then I go straight in.
This is the login code:
function login()
{
FB.login(function (response)
{
if (response.authResponse)
{
// connected
var authResponse = response.authResponse;
access_token = authResponse.accessToken;
refresh();
} else
{
// cancelled
}
});
}
One hint in this problem is when the facebook dialog screen appears,
it only asks for my username/password. It doesn't ask go to the usual
screen where Facebook asks for you to give permissions for "Basic
Information" etc. It's just a username/password screen and then I go
straight in.
This is because you've already authorized the app, so once you login it will take you straight to the app.
It works fine when I do this, but if I try to log in with a different
account, no data for the feed is returned.
Well the limited view of code you posted is fine, so something else is the problem. First debug step is to get the access token for that different account, and check the debugger to see if its tied to the appropriate user and scope.