Twitter: raymondcamden


Address: Lafayette, LA, USA

Adding Parse.com User support to your PhoneGap application

10-31-2012 11,520 views Mobile, JavaScript, HTML5 48 Comments

A few days ago I wrapped up my series on integrating Parse.com support with PhoneGap. Now that I've got a good handle on the basics, I thought I'd begin exploring some of the other features. Today I'm going to share an example of adding User support.

Before we get into the code, let's talk a bit high level about what Parse does for User management. Even if Parse did absolutely nothing, you could still easily create "User" types and do your own authentication. But Parse actually provides support for pretty much every User-related need you can think of.

  • First off, Parse supports "User" as a special type of object data. Using this object type will give you a few built-in properties and other features as well.
  • Parse has special methods for registering and logging in.
  • Parse supports automatically encrypting passwords for you.
  • Parse handles email information as well, and will block users who attempt to register with an email address already used. To be clear, email addresses are not required for working with users, but if you do choose to use them, Parse ensures they are unique.
  • Speaking of emails, you can also enable email verification for your users. Parse handles sending the email. Parse handles responding to the verification on the web site. Finally, Parse's API supports recognizing when a user needs verification and doesn't have it yet.
  • If you do use emails with your users, Parse supports a password reset workflow. They don't document what this looks like, but I took screen shots and will share them below.
  • Lastly, Parse can also automatically cache user credentials on the client. This is done in LocalStorage and is encrypted in case someone gets access to the machine.

That's the high level overview, so let's get into the code. For my demo, I decided to build an application that supported registering new users, logging in existing users, and storing simple "Note" objects. These Note objects should be tied to a user so that I can't read someone else's notes. I began by creating a simple home screen.

Clicking on the Register button takes you to a simple form.

As I mentioned above, Parse has a special User type. At minimum, it requires a username and password. Email is supported too, and has special consequences. You can also add anything else you want as well, including birthday, gender, and so on. For my demo I just went with the basics. Let's look at the code that handles the submission of this form.

The beginning of this function is pretty boilerplate. Get the values, do some basic validation, etc. Note though the creation of the Parse.User() object. This differs from regular Parse object creation. The API to set values though is the same.

The signUp method is what handles user creation. The first argument you can ignore (as I did in the code). Look at the result handlers though. For a successful creation, I store a copy in the global scope (that currentUser object was defined earlier) and then simply load the main application page. (You can ignore the "cylon" call there - I'll explain that in a note at the end.)

The error function will get called for all possible cases you can imagine. User already exists? You get an error. Email address already exists? You get an error. You get both an error code and a message. Oddly the message is all lowercase. In production applications I'd probably use the code and handle the messages yourself, but to keep things simple I used it as is. Here is an example.

Let's switch now to the login form. Here's a screen cap.

As you can see, I've got both a login form here as well as a reset password form. Note that while Parse requires a username, the email address is optional. You can also skip asking a user for a username and just ask for their email address. You still store it as a username, but if you want to make the email address the username, that is very much supported as well. Let's tackle login first.

As before, we've got a bit of simple form field grabbing and checking in the first half of the function. The logIn function is where the fun is. You pass in the authentication values and then handle the success or failure. For the most part we handle this the exact same way as registration. If we're good, store a copy of the user and then load the notes page. Otherwise, report the error. In case you're curious, the messages here are lowercase as well.

So what about password reset? The code for that is equally as simple.

As before, almost half of the code is simple DOM manipulation. The Parse API has a simple method to call and our work is done. In case you're curious, this is the email you get:

"notebook" is the name I gave the application. Normally you would have something much more descriptive.

Once clicked, you end up on a pretty simple page on Parse.com.

And finally, you get this when done:

So just to be clear, at no point did you need to actually email your user. You didn't need to set up an email account. Nor did you need to set up a web server. I do think Parse.com should perhaps offer a bit of customization here, perhaps for paying customers. I'd imagine it would be nice to be able to include an application logo of some sort, and perhaps add a bit of verbiage to the screens.

Oops! I just checked, and yes, Parse.com gives you access to modify the email templates as well as the web page templates. Kick. Ass. This is paid-level access only (specifically Pro/Enterprise), but the options definitely exist. They even have a way to host the files on your own server (well, host an iframe) so users never see a Parse.com URL.

That's login, registration, and password reset. I hope you agree - it's damn simple. I mentioned earlier that Parse can cache authentication information on the client. You can write code to check for this easily enough:

This is an optional feature though and you do not have to make use of it. As I said, it makes use of LocalStorage. I had a key named this:

Parse/av8jY0rm4qrXl3dBGLf9odznxbhuqHhiiH6s8Gxn/currentUser

with a value of:

{"username":"ray1","email":"raymondcamden@gmail.com","_id":"fwjEd2UStM","_sessionToken":"kkfwkr3va2hvd16t58vjl4ypq"}

Ok - we've covered registration and authentication. What about data? You've got a few options here.

First off - Parse has a rich access control feature. You can provide various access levels (ACLs) on every piece of data in the system. Parse also supports Groups as well, but I'm not covering that in this entry. At a basic level, if you want to create an object that only the current user can read, it takes one line of code:

someObject.setACL(new Parse.ACL(currentUser));

While this works, you also have another option, which is to simply add a "owner" type property. So for example:

someObject.set("creator", currentUser);

Personally, I think it makes sense to use both. You're explicitly saying "Ray made this" as well as "Only Ray can read this". Together it makes getting your data to a specific user that much safer.

To test this, I added a simple form that allowed you to write some text, the note this application was built to support.

And here is the code that handles creating the object. As I said, I made use of both methods of linking the data to the user.

Conversely, getting my notes requires simply adding the current user as a filter. Because of the ACL, if a hacker (or script kiddie, like me), modifies the user values somehow or just does a query without the filter, the ACLs will kick in and ensure I can't read someone else's content.

And... that's it. Before I leave you though, let me share a few tips. First, you want to read the official docs yourself. I didn't cover everything so take a look yourself.

Secondly, Users are called out in your dashboard. You can even manually change passwords there, which was helpful during testing.

Thirdly, don't forget what I said in my last series. You have options to block anonymous users from doing anything with your application at all.

Lastly - Parse.com also supports Facebook and Twitter integration. That's what I'll be covering in my next entry.

Full code of my ugly, but usable, demo application is below.

Ok, a quick side note. You can stop reading now if you want and won't miss a thing. When I built this application, I wanted a simple way to handle having a 'single page' frame for my application. By that I mean, when you clicked the Login button for example I wanted to do an Ajax-call for the content and load it in. In other words, once you hit index.html, you never actually leave that. jQuery Mobile is perfect for that. But... I kinda wanted to try something different. I wanted JQM-like navigation with zero UI changes. I whipped up something I called Cylon. Dumb name, I know. But it was kinda fun to build. I doubt if I'll open source it (well, technically, you can grab the source in the zip and use it if you want) but I wouldn't mind any feedback on the code if you want to give it a shot.

Download attached file

48 Comments

  • bender #
    Commented on 10-31-2012 at 6:13 PM
    Hi, awesome blog. Can you please tell if its possible to download data that is hosted on parse (in case you move to your own server)
  • Tom #
    Commented on 10-31-2012 at 6:42 PM
    Hi Ray:

    Awesome introduction to Phonegap+Parse User. Is there any possibility that you would cover Phonegap+ParseFacebookUtils?
  • sam #
    Commented on 11-01-2012 at 4:02 PM
    awesome article! I would love to see this incorporated with Facebook authentication as well..
  • Commented on 11-01-2012 at 4:02 PM
    Bender: Absolutely. That's one of the best features. If you are worried about Parse going bankrupt or just want to keep a copy, you can export data right from the dashboard. I thought they had an API as well, but I don't see it.

    Tom: I plan on covering Facebook and Twitter next.
  • Brandon #
    Commented on 11-07-2012 at 10:37 PM
    Great blog! I've found a number of your blog postings very helpful.
    Have you done any in-app purchases with phonegap and parse yet?
  • Commented on 11-08-2012 at 6:21 AM
    Nope, not yet. Ecom stuff is a bit harder to test normally. ;)
  • Tim B #
    Commented on 11-09-2012 at 2:50 PM
    I tried opening the zip package in chrome but the ajax didn't work. Packaging it into a phonegap app then opening it in the android emulator made it work. Is there any way to run it from a browser?
  • Commented on 11-09-2012 at 2:54 PM
    If you can't run it from a local web server, try with this Chrome command line:

    (obviously this is for Mac, you can tweak for PC)

    open -a /Applications/Google\ Chrome.app --args --allow-file-access-from-files --disable-web-security
  • Tim B #
    Commented on 11-09-2012 at 2:58 PM
    K, I tried the command line but no luck. I went ahead and looked at the cylon.js file. It looks like its only listening for touch events and since I can only send click events in chrome it won't work unless I switch it to jquery mobile or tweak the js.
  • Commented on 11-09-2012 at 2:59 PM
    Oh, in Chrome, open dev tools, go to settings. There is an option to emulate touch.
  • Tim B #
    Commented on 11-09-2012 at 3:10 PM
    Sweet that worked.

    Also the app isn't allowing me to register or login, no errors. It appears as though its not communicating with Parse. Do I need to recreate your DB and enter my own Parse API Keys. Or is it a matter of adding the parse android jar to my phonegap app and redeploy?

    Thanks
  • Commented on 11-09-2012 at 3:19 PM
    It should work. DO you see anything in console?
  • Tim B #
    Commented on 11-09-2012 at 3:26 PM
    Nope, the console is clear, no errors. However I just deployed it in the android emulator and its working. Just not working in chrome, I guess.
  • Commented on 11-09-2012 at 3:31 PM
    Weird, I did all my testing there. Well, just happy you got it.
  • Tim B #
    Commented on 11-09-2012 at 3:32 PM
    Maybe its a pc thing :)

    Anyways, thanks!
  • Commented on 11-14-2012 at 4:17 AM
    Parse keeps on getting better, I haven't looked into the User side of things yet, but reading this is making me wonder why I bother with a MySQL database at all any more.

    I know you can do basic queries with Parse, can you get really complicated with Joins and Subqueries?

    I'm leaning towards ditching my server and just having simple web site hosting and using Parse for everything else.
  • Commented on 11-14-2012 at 5:01 AM
    Ok, so I read through the docs, relational objects and queries are all possible and look pretty easy to do.

    I need to be using Parse more.
  • Commented on 11-14-2012 at 6:26 AM
    Glad you like it. :) I still plan on doing Twitter/FB integration soon - just have other stuff in the pipeline.
  • Commented on 11-15-2012 at 1:42 AM
    Great site and great tutoials.

    How would I make it so that once the user is logged in, they can see all the notes? Sort of like a rough forum.
  • Commented on 11-15-2012 at 8:56 AM
    Justin, I talk about getting "your" content at the end of the blog entry - does it not make sense?
  • Alex #
    Commented on 12-20-2012 at 12:11 PM
    Still looking forward for your promised parse.com <-> Phongap login integration through parse facebook user management without the need to open a Website. Its not that easy... but would be incredible usefull
    Sincerely,
    Alex
  • Commented on 12-20-2012 at 12:14 PM
    Still planning it. Life got super busy. I had hoped things would slow down before XMas, but I've got some big presentations right after the break. It may not be done till mid Jan.
  • sam #
    Commented on 03-13-2013 at 5:57 PM
    Are you still going to do a FaceBook or Open Id integration?
  • Commented on 03-14-2013 at 6:43 AM
    I still want to. Just not sure when.
  • Steve #
    Commented on 04-23-2013 at 12:02 PM
    Really good stuff. Considering having a free version of my app -- which currently calls a .net Web API service to do look up some values on my SQL Server (hosted) db and perform some math before sending results back to phone.

    As for a paid version of the app, Parse seems to be a good way to have a db of paid users and to handle authentication, keeping the Web API & SQL Server stuff as is.
  • Rigel #
    Commented on 05-27-2013 at 9:56 AM
    Hi I am trying to use parse-1.2.7 with ember tool. https://github.com/rpflorence/ember-tools/ when I include Parse from cdn it works fine. But when I download a copy it gives me error of list of dependencies like failed to require LocalStorage, xmlhttprequest. I am using LAMP. I am noob can you give me some pointer.
  • Commented on 05-27-2013 at 5:52 PM
    I'm sorry, but I don't use Ember.
  • Pratik #
    Commented on 06-21-2013 at 7:12 AM
    Hi I am trying to do the same thing using trigger.io , can u please help me with this ? how can we create same thing using parse.com and trigger.io.

    thanks
  • Commented on 06-21-2013 at 8:33 AM
    I don't know trigger.io. Can you read their docs and share your experience?
  • Pratik #
    Commented on 06-24-2013 at 1:47 AM
    Hi Raymond ,
    I tried the this tutorial on phonegap build . i am getting an error saying "connection to server was unsuccessful "
  • Commented on 06-24-2013 at 7:40 AM
    You got that on PhoneGap Build, or did you get it when you ran the app?
  • Pratik #
    Commented on 06-24-2013 at 10:31 AM
    Yes i did this in phonegap build ...but was unable to get through login and registration screen ..and was not able to see any data in parse.com ..
    I am trying to do user support but a slight difference in the third page ..i mean instead of uploading and saving notes ..i want to upload music files .
  • Pratik #
    Commented on 06-24-2013 at 4:36 PM
    Hello , i think i am going wrong somewhere.
    i also tried this by downloading the source code zip file .. updated the application id and js key from parse . but still wen i run the app on my phone ..i can see the first screen and when i click registration , fill my details and hit register button then it again takes me back to the first screen with login and registration button , the same thing happens even when i click login on first screen ..and as soon as i fill details and hit login button it takes me back to first screen .

    Please help me

    Thanks
  • Commented on 06-25-2013 at 8:26 AM
    I'd suggest running this via the Ripple emulator so you can use the Chrome debug tools. That's all I can recommend from here.
  • Pratik #
    Commented on 06-25-2013 at 10:15 AM
    Thank you Raymond ..
    I tried your another stuffs u blogged regarding integrating parse with phonegap ..
    all those tutorials worked even the offline support with parse but I am just unable to get this run successfully.

    I am not getting the point where I am going wrong ..Please suggest me. .

    Thanks
  • Commented on 06-25-2013 at 10:19 AM
    Pratik, did you see my comment? You need to try running this using Ripple and use Chrome's debug tools to try to diagnose what the error may be. I've got a blog post on using Ripple as well as ones that talk about Chrome Dev Tools. I can't just tell you what's wrong.
  • Pratik #
    Commented on 06-25-2013 at 10:21 AM
    When i tested this in my android phone , i was not able to see any validation messages or error messages related to username and not even reset password thing is not working ..
    and mainly I am not getting any data in parse .
  • Pratik #
    Commented on 06-25-2013 at 10:24 AM
    Ok Raymond , Will test this in ripple and will check and get back to you.

    Thank you
  • Pratik #
    Commented on 06-25-2013 at 12:11 PM
    Hello Raymond ,

    I tested the code in ripple emulator and this is the error message i am getting -
    "Validation Failed"

    "Config.xml file could not be found in the application's root or is malformed xml"

    and in developers tools ..

    the error I am getting is this .
    "Uncaught type error : cannot read property 'type' of undefined"
    inside this function

    ++++++++++
    function deviceready() {
    console.log("device ready to roll");
    if(navigator.connection.type == Connection.UNKNOWN ||
    Uncaught TypeError: Cannot read property 'type' of undefined
    navigator.connection.type == Connection.NONE) {
    //handle user being offline
    } else {
    console.log("Initialize Parse");
    appReady();
    }
    }
    .
    +++++
  • Commented on 06-26-2013 at 2:39 PM
    Ensure you are using the latest PhoneGap SDK/JS file.
  • John #
    Commented on 05-19-2014 at 4:11 PM
    I know this is an old post, but I came across it and tried it out but haven't been able to get it to work yet. I've tested on a local server with ripple, and even tested on a live server with ripple and the browser on my phone. I connected my parse.com account to it and whenever I enter my username/password and hit login it just refreshes to the login page.

    Any idea what could be causing that?

    Thanks
  • Commented on 05-19-2014 at 4:20 PM
    Do you see anything in the console?
  • John #
    Commented on 05-19-2014 at 4:21 PM
    No, that's the weird thing, nothing is thrown in the console, it just goes right back to the first page. I even updated to the latest version of Zepto.js
  • Commented on 05-19-2014 at 4:24 PM
    Maybe add 'preserve log' to your console settings and see if it is being cleared away. Is it online where I can run it? I can just fire deviceready manually.
  • John #
    Commented on 05-19-2014 at 4:27 PM
    I've got it hosted online here:http://southarealearning.com/copy/index.html

    I basically just changed the App key and JS key then uploaded it to see if it worked or not, since the custom one I built based off your tutorial wasn't working.

    Thanks,
  • Commented on 05-19-2014 at 10:08 PM
    You want to make sure you install the connection plugin for PhoneGap. Did you ?
  • John #
    Commented on 05-20-2014 at 7:05 AM
    That could be what is causing the issue then, I don't know what that means, I was trying to run everything from the web, not run it through phonegap to create a stand alone app.
  • Commented on 05-20-2014 at 7:08 AM
    You need to read my blog article on PG3 and plugins: http://www.raymondcamden.com/index.cfm/2013/7/19/P...

Post Reply

Please refrain from posting large blocks of code as a comment. Use Pastebin or Gists instead. Text wrapped in asterisks (*) will be bold and text wrapped in underscores (_) will be italicized.

Leave this field empty