Reputation: 2220
I have a RESTful service which I have secured using Spring Security
and pac4j-oauth
. An important detail is that Google is acting as the OAuth2
server-- we need the user's Gmail address to know if they are a legal user of our system, and eventually the service will also need access to their calendar.
When the user first accesses a protected resource (typing in the URL) they get redirected to Google. Once they have authenticated they get redirected back to our service. This works fine.
The problem is that I want to call the service using Ajax
. When I issue the first Ajax
call it gets back a redirect to Google. This could mess up the Ajax
call but in fact it doesn't even get that far. The browser sees the redirect and throws a CORS
error: "No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://localhost:8443' is therefore not allowed access."
I'm at a loss how to handle this. Suggestions would be welcome.
Some thoughts:
If I replace the regular Ajax
call with a JSONP
call, the redirection still causes an error (because it returns a URL instead of a JSONP
script) but maybe the client could detect that and navigate to Google on behalf of the service? Once the user authenticates, the client could then take them back to the protected resource again?
This feels wrong though. For one thing it means that future Ajax
clients of the RESTful service would have to jump through the same hoops. I'd prefer the clients not to have any dependencies on the server's security implementation.
While CORS
errors are common enough, I've only found a couple other people complaining about them specifically with OAuth2
authentication. So I'm also wondering if we took a wrong turn with our architecture somewhere. What exactly are we doing that's so unusual?
Any insight would be appreciated.
Upvotes: 1
Views: 4087
Reputation: 2220
After more investigation here are my conclusions.
I'll start with #2 first. Yes, we probably took a wrong turn. Specifically, OAuth2
was designed for authorization, not authentication. (Though if we had been running our own OAuth2
server we might have gotten away with it.)
Google supports authentication of course: see their docs for Google Sign-In. But note the two options they list.
RESTful
service. So the plan is that we'll have one webpage that offers the option to authorize our services to access their Google calendar. The user will click on the link explicitly to get the authorization from Google-- the RESTful
service won't need to redirect their browser. This avoids the CORS
problem. The client will then post Google's access token to our RESTful
service.
Note that other consumers of our service don't need to implement this, they just need to let the user authenticate in a way that doesn't require a redirection to a third-party. Initially we'll use our own user/pwd database, with an eye towards hooking into a company directory or SSO
in the future. Spring Security
supports numerous options of course.
So: we had to compromise our original plan, but now we are dealing with flows that are well documented and have sample code. So I expect things will go much smoother from now on.
I hope this helps someone avoid the same OAuth2
design mistake we made, namely using it with a third-party to authenticate users of our RESTful
service. There are more appropriate ways to authenticate users.
Upvotes: 1