My goal is to build a standalone RESTful Rails 3 service that communicates with a Rails 3 web application via ActiveResource JSON and an iPhone application via iOS 5 native JSON. I have each running so that a single table of data is being exposed in the service app and that can be called and rendered via both a Rails app and the iPhone app.
My question is around authentication and something that can be reusable for both the web application and the iPhone app or in the future an Android app.
From the research I have done on this site, it seems HTTP Basic would work for both, however I would be unable to properly logout a user on the web side like sessions or cookies could and I have the browser login form to deal with. If I use sessions, how would that translate to setting up authentication on the iOS side of things?
This project is a code learning exercise, so I am hoping for implementation or architectural guidance rather than simply implementing Devise or Authlogic, etc.
It sounds like you're conflating at least two problems.
The first issue is authentication: you need to determine if the user is who they say they are. For authentication, you can do basic auth. You could also use client certs, though that's probably not what you're looking for.
The second thing is session management: First, you can do basic auth on each page request and store the session state in the database, but you're right about not being able to log the user out, as the browser will cache the credentials.
You may want to consider a login page that requires basic auth and shoots back a cookie to do session management. All other pages don't require basic auth, but give a 401 unauthorized if the cookie isn're present. Or you could redirect. The iOS client code will have to know to call the login page first to get the cookie and then use it after that. Logging out is deleting the cookie.. hrmm, but the browser will still cache the basic auth credentials.
I'm thinking the only way you're going to get what you want is to have a form-based auth for your web users (to allow them to log out and log in as someone else), and a basic-auth based system for iOS users. As a result of both authentication mechanisms, return a cookie that has to be used for all other pages.
Related
tl;dr; see the question below
In my app, I have a login that uses SFSafariViewController and ASWebAuthenticationSession that follows the OAuth 2.0 flow (Using the AppAuth library).
The login works and the cookies are shared with Safari as expected. Thanks to the cookie sharing, users are automatically logged-in if they use the Safari app.
However, back in the app, if I launch a SFSafariViewController again, the cookies are missing. This surprises me, because I thought the cookie Store is the same for SFSafariViewController and Safari, and it clearly worked in the direction from SFSafariVC to the Safari app during login.
Is it intended not to work the other way round - from Safari to SFSafariViewController, or is it a bug?
I have not found clear statements in the documentation.
Of course I have not set ephemeral session to true, but according to the documentation it would do the opposite of what I want to achieve:
When not using an ephemeral session, all cookies except session cookies are available to the browser.
I've also found somehow related radars like http://www.openradar.me/33323462 and http://www.openradar.me/radar?id=5036182937272320 or this stackoverflow post: Why is SFSafariWebViewController not sharing cookies with Safari properly? but they do not answer my question.
According to this comment it could work if the cookies have an expiry date (set to a future date). I verified the cookies - they all have a future expiry date.
My question: Am I doing something wrong, or is this expected behaviour, that SFSafariViewController does not get cookies from an earlier SFSafariViewController instance in the same app or from Safari?
REQUIREMENTS
So it seems you want a solution to invoke secured web content from a mobile app, and to avoid an extra login. It is a common requirement and I will be adding some stuff to my blog on this topic over the next month or so.
STATE OF THE INDUSTRY
The problem with the above is that third party cookies, such as those issued by Identity Providers, are often dropped by default these days due to browser security initiatives such as Intelligent Tracking Prevention changes - which is ON by default in Safari:
COOKIE PROPERTIES
Worth checking that your cookies are issued with SameSite=None, which will give you the best options for a third party cookie based solution.
MOBILE FIRST DESIGNS
In an OAuth world, in order to meet the requirements, it is likely to be necessary to send a token from the mobile UI to the web UI, which of course has prerequisites that need to be designed for:
Web UI must use tokens
Web UI must use different strategies for token handling depending on the host
OPTION 1
One option is to use a mobile web view to show the web content - see my code below:
Web UI Code to ask the host for tokens
Mobile UI Code to service these requests
OPTION 2
Another option is to send something representing the token in a query string parameter from the mobile app to the Web UI, in which case you need to ensure that:
No usable tokens are recorded in web server logs
The token has a one time use only
A typical implementation would look like this:
Mobile UI calls an /api/token/encrypt endpoint
API stores a token hash in a database and returns an encrypted value with a short time to live
Token is sent from the Mobile App to the Web UI
Web UI calls an /api/token/decrypt endpoint to get the real token
The API's decrypt implementation deletes the database entry
I created a new ASP.NET MVC WebApplication in Visual Studio 2015 with the options to use School or Work Accounts to authenticate against an AzureAD. This worked fine.
Then I converted the Project to an App for Office Project as an Excel Task-Pane Add-In.
Then when I start the Application it starts an Excel Spreadsheet with a taskpane showing the request to login with Microsoft. When selecting an account or choosing to log-in with another account I get redirected to login.mocrosoft.com in a new Browser but receive the following error:
IDX10311: RequireNonce is 'true' (default) but validationContext.Nonce
is null. A nonce cannot be validated. If you don't need to check the
nonce, set OpenIdConnectProtocolValidator.RequireNonce to 'false'.
The URL shown in the new browser is "https://localhost:44300/" since I am debugging locally I take it.
Is this an issue because the authentication originates from the Task-Pane? Is the Task-Pane the same as an iFrame? If so it could be a similar issue as the following problem: OpenIDConnect Azure Website hosted in an iFrame within Dynamics CRM Online
Can I simply set the RequiredNonce to false? If so how?
Please help me to create an App for Office with Authentication against an AzureAD / Office365Domain? The AzureAD I am authenticating against is my private Free MSDN Subscription currently, wanting to use the company's Office365 AzureAD in future.
I am using Office2016, VS2015, Microsoft.Office.js Version 1.1.0.9.
First, it is feasible to do what you are looking for, have a look on my add-in: Keluro Mail Team. Keep on working, you'll manage to make things work^^.
Step1
First, start with the most simple scenario: your auth process should work in a standard window we sill see the sandboxed iFrame later. Check your OAUTH flow when browsing your 'app directly', i.e. test your authentication as a plain regular web app which is served in your case at https://localhost:44300/". To avoid javascript errors remove all Office.js related stuffs and the Office.Initialize function.
From the error message dealing with Nonce, I bet you are implementing a code authorization flow. This should be more or less something that looks like this sample. In this code authorization flow, the token and the REST requests are made by your server using an authorization token. Meanwhile authentication between your server and your web app is made with a plain old asp.NET cookie (in the sample above at least). This scenario is OK for our purpose, I use it too. To complete this step, try to request some basic stuff that is not related with Office.js but only with the Office 365 REST api. In one word forget that your developing and Office add-in, image you are developing an Office 365 web app.
Step2
Now that you completed Step1 you can go for step 2: make things work in a sandboxed iFrame within Office. Have a look at this blog post from Richard DiZerega. This is the most reasonable approach to handle OAUTH flow in a sandboxed environment. If you are using the sample mentioned in Step 1 above, the authentication between your server and your app is made using an asp.NET cookie. Following, Richard's guideline you could keep it in a server-side cookie dictionary after the popup OAUTH flow is completed and then set it in a request from the original iFrame. To recognize that the two windows correspond to the same user you can generate (cryptographically secure!) an id that you can pass in the two requests (parameters are encrypted in https). Ok that is complicated but it works. The SignalR technique Richard talks about is a plus for user experience but is not mandatory, that could be a Step3.
I solved my issue by adding https://login.microsoftonline.com and https://login.live.com to the App Domains in the App Manifest. I dont understand the technology, so I cannot comment on why this works, but the solution works for me.
I have a website that users can log into to see their account info.
I would like to build functionality into my iOS app that allows them to log in and see their info in the app. The usernames and passwords are stored in a SQL database.
How can I authenticate the username and password the user types into the app with the database?
If you have better atuthentication system in your web..
then i would prefer you to use the WEBVIEW for your login page. and continues the other using the normal app flow.
there are lot of tutorials for creating username and password login Function in IOS. i dont know whther you are basic or new progrmmer. But try this you may get some idea.
http://www.youtube.com/watch?v=HrZR2SyeoSk.
You can go with JSON serialisation, if you experienced to load data from server.
There are multiple ways you can go about this but at the end of the day you need an endpoint for your iOS application to talk to your web server. This can be done with a TCP connection (little more complicated) or with a RESTful HTTP API endpoint which is generally the way most developers will go.
To get you running up and quickly on the client side have a look at AFNetworking to do the heavy lifting on your HTTP requests. You will then need a URL on your website that the iOS application can query. Abstract things to keep your API on a different subdomain, say for instance by creating a subdomain to handle your API requests. A login example could look like this
http://api.mysite.com/login
For a PHP based REST API here is a tutorial for you, PHP API or you could use a Node.js framework such as Restify
The general practise is to use JSON encoded data when sending requests back and forth from the server, iOS 7 has built in JSON encoding/decoding, node and PHP also have pretty good support.
Once you are able to send and receive HTTP request from your iOS device to your web server it is just a matter of checking the username and password match up on the server side (seems you already know how to do this?) to the ones in your database and sending back a authentication BOOL and option error message if failed.
To my understanding creating a smartphone apps based on a site is to simply create an API for the website and to output the data in XML, JSON. In my case JSON has Ruby on Rails has it built it in it. In theory all I have to is to read the event.json page and read the attribute and on phonegap to read it and build a logic from it.
However, in my phone app, I would like to allow user to log in before entering and in fact on the web-base I am using the devise gem to manage my user management. How am I supposed to allow user to log in from device using phonegap? Should I read an API JSON that showcase all users but then that may cause a lots of security issues, is there a device documentation on that specific issue, or should I scrap device and just make an authentication system from scratch?
Devise provides for an auth-token to be used for login. This works well with JSON APIs as you can set a header to include the auth-token to identify the user. Your login form would just be responsible for getting an auth-token from valid credentials. SSL can help to secure this information on the wire.
I created a Gem based on rack_iphone which store the session
in the localStorage and and upon opening a application from a home screen shortcut
the application take the cookie if present from the localStorage and the sent it to the server
Hope this work for you
I'm working on an app using facebook & oauth. The app lives inside a facebook canvas, and the authentication is done server side. The app is done w/ Ruby on Rails 3.2, using Koala for dealing with the api (and mongodb as backend, for what it's worth), and hosted on heroku.
So, I supply the heroku url as redirect_url for the callback. Which makes the user go out of the canvas after the authentication, and well, I want it to stay inside. I read a few threads about this that suggested I redirect to the canvas url with js once the authentication is done. I did that, but now it seems that my session token is never set, and the user goes through the auth flow every time he tries to see a non-public page (which means he loops on the welcome page, having an "invisible" exchange with facebook each time).
I don't really get what I'm doing wrong here, so any help is welcome. If you need more informations, just ask.
Thanks for your time!
So I found what was my problem : the page my canvas pointed to was a "public" page, and did not handle anything authentication related, meaning it didn't parse the signed_request, or anything else. I ended up setting a special endpoint for the canvas in charge of handling the signed_request logic, and now it works as one would expect.