JWT: handling token auth on a multi-domain-level - javascript

Currently I'm facing the following problem:
I'm building an application with a standalone login view.
Let's assume they both run on different domains. My login view communicates with a REST service on the server that issues a JWT token.
With this issued token the user should now be able to view (be forwarded to) the application. But this application - as mentioned - runs on another domain (or subdomain, maybe).
In my mind I tried the following:
Token is issued by the server. A hash is stored in a database and the hash is issued to the user. The hash is transferred to the application via URL and the applications checks the hash.
Token is issued by the server. The token is transferred to the user. When the user now opens the application (or is forwarded to...) the token should be transferred there, too. I have no clue how to do...
Both are not ideal ways, i know. But I really don't know how I can achieve that...
I hope anyone is able to help me with my thinkings?
If anything is unclear, just comment.
Thanks in advance!

Facebook, Twitter, Google, etc. offer OAuth by redirecting (302 Redirect Request). Basically your app starts if user has a valid token everything is fine, else it will open the Login-Page from the Identity Provider (e.g. Google) and return the token, if the login was successful.
This graphic shows the general steps:
https://www.soapui.org/soapui/media/images/stories/oauth2/oauth2flow.png
Hope this helps.
Lets assume you have two services in 2 different domains. One is your identity provider which generates tokens and holds the token <--> user assignment (we call it: idp.my.company). The other one is any application that does stuff but needs to login via idp.my.company (we call it app.my.company).
You have two scenarios:
1. Login without having a token aquired before.
2. Login with token.
Request GET: app.my.company
Response 302: Moved to: idp.my.company
Take a look which redirection type follows your needs (307 maybe)
https://en.wikipedia.org/wiki/URL_redirection
You need to add an information where to redirect back. In this case app.my.company.
[This happens automatically because of the Redirect] GET: idp.my.company/login.html.
Response 200 OK: idp.my.company/login.html
The User will now see the Login-Page of your IDP-Service and perform a Login.
Request POST: idp.my.company/login.html (or whatever)
The User posts his credentials to aquire a token
Response 302 Redirect: If login is successful, return token and now redirect to the origin site (app.my.company) which you provided earlier.
Request GET: app.my.company/afterlogin.html
The header contains a valid token
Response 200 Ok: Now the app.my.company service needs to check if the token is valid and if true return 200 Ok otherwise redirect again to IDP (start over at step 2).
This should be it. There could be errors but you should have a consistent picture of the process and get a grasp on how to implement it. Those steps cover scenario 1 and 2.

Related

How to connect to the Paypal API through Javascript using OAuth?

I want to make a small app that gets some account information from Paypal and shows that in a HTML page. I solely use HTML/CSS and Javascript, I dislike to run the authorization flow on the server for security implications. I don't want to have the token on the server.
I have a working setup now using the OAuth code grant flow provided by Paypal (more here), but as described above, I want to cut the server out of the picture.
There are some methods described in the page I just referenced, but none seem to implicate there is an implicit grant possible.
Is it possible to use Paypal with OAuth implicit grant or something similar?
(The current answers are taking the code grant flow, which was specifically not what I asked for. I know that one exists, but it is bad to use it in this case, so please only answer if you know a method without the need to provide the OAuth secret token to the client.)
If anyone does not understand what is/how works Implicit grant
Of course this is posible with plain Javascript but is not recommendable. Paypal has an endpoint to provide auth tokens:
https://developer.paypal.com/docs/integration/direct/make-your-first-call/#get-an-access-token
Also you will need to obtain user's consent.. When performing the request you should provide redirect_uri param with your webapp url. Usually developers tend to store returned values on the server script that receives that response from paypal. But it is not necessary coz you are able to read javascript global var location which contains all params.
How PayPal uses OAuth 2.0
EDIT:
In order to achieve this you have to do the following steps:
VARIABLES:
APP_CLIENT_ID -> your app's client_id
APP_SECRET -> your app's secret code
APP_RETURN_URL -> default endpoint of your app MUST BE equals to redirect_uri
OPEN_ID -> returned code that allows to create a token for specific customer, also to retrieve info from the user
Asuming that you've created an APP in developer.paypal site to obtain "client_id" and "secret" in order to build an url to redirect the user to paypal login form.
Redirect your customer to:
https://www.[sandbox.]paypal.com/signin/authorize?client_id=APP_CLIENT_ID&response_type=token&scope=openid&redirect_uri=APP_RETURN_URL
Customer will log in its account and produce a openid that it will be sent back to your app through http: 302 redirect to redirect_uri which should be your app.
APP_RETURN_URL?code=OPEN_ID&scope=openid
back in your app you can use that code to perform a request to create a token.. and is up to you:
You're able to retrieve profile data from the user such as address, phone..
request:
curl -v https://api.sandbox.paypal.com/v1/oauth2/token -H "Accept: application/json" -H "Accept-Language: en_US" -H "Authorization: Bearer OPEN_ID" -u "APP_CLIENT_ID:APP_SECRET" -d "grant_type=client_credentials"
response:
{"scope":"https://uri.paypal.com/services/identity/proxyclient https://uri.paypal.com/services/subscriptions https://api.paypal.com/v1/payments/.* https://api.paypal.com/v1/vault/credit-card https://uri.paypal.com/services/applications/webhooks openid https://uri.paypal.com/payments/payouts https://api.paypal.com/v1/vault/credit-card/.* https://uri.paypal.com/services/identity/grantdelegation","nonce":"2017-05-05T14:33:28Z488Zx8aUM1aSVo_wpq8IOecfccJMHptR1PVO2OpWcbA","access_token":"A21AAHZCMP5vBuLMzz2m78DJGZhhpmu854amEVEO5WOavfk1GlNl_gmjSi01_69tJLRi5N_6pT-3GpRqZ81_pD1qKIAGANHMQ","token_type":"Bearer","app_id":"APP-80W284485P519543T","expires_in":32400}
Then you're able to follow this: https://developer.paypal.com/docs/integration/direct/make-your-first-call/#make-an-api-call

Google HTTP/REST OAuth: authorisation code request has state for db user, access token request has none

I am using the OAuth server flow for Google.
It starts with the user clicking a link that runs javascript to open a popup with the following request in the URI which is all working great:
var endpoint = "https://accounts.google.com/o/oauth2/auth";
endpoint = endpoint + "?scope="+encodeURIComponent(googlecalendar.SCOPES);
endpoint = endpoint + "&redirect_uri="+encodeURIComponent("https://myserver/google/");
endpoint = endpoint + "&response_type=code";
endpoint = endpoint + "&access_type=offline";
endpoint = endpoint + "&approval_prompt=force";
endpoint = endpoint + "&client_id="+encodeURIComponent(googlecalendar.CLIENT_ID);
endpoint = endpoint + "&state="+encodeURIComponent(googlecalendar.USER_ID);
On the server side, I get the state which contains the user_id for my DB and the authorisation code.
Now I want to exchange the authorisation code for access token (and renew token). This will be a HTTP request with a redirect URI, no state parameter is included.
The problem is that when I get those, I will need to store them against a user in my DB, but I don't have any way to check which user the callback is for.
The best I was able to come up with is using the token to query the google user's identity it belongs to but this still won't help me to find the user in the DB.
Can anyone help me with this flow? There must be some way to do. I don't want to use client libraries because later when I need to create watchers the PHP client library does not include this for the calendar API.
Short Answer
Despite the presence of a redirect parameter, the access token will generate a standard 200 response, not a 301 redirect. Depending on how you issue and handle the request/response, you can preserve your state.
More Detailed Answer
According to section 4.1.4 of the OAuth 2.0 spec document (RFC 6749), the response to an Access Token Request should be an "HTTP/1.1 200 OK".
In other words, the server will not perform a redirect, meaning you can issue a request and process the response in the same scope (either in the client or server, whatever your situation), so your database user ID need only be in local memory.
This is different from the Authorization Request, which is supposed to result in an "HTTP/1.1 302 Found" (redirect). See section 4.1.2.
So why is the redirect_uri parameter required?
According to section 4.1.3, the server must:
ensure that the "redirect_uri" parameter is present if the "redirect_uri" parameter was included in the initial authorization request as described in Section 4.1.1, and if included ensure that their values are identical.
In other words, the redirect_uri acts as a sort of secret or password which the server must use to verify the access token request. If the client fails to provide a redirect_uri parameter, or the parameter value is different from the original request, then the server must reject the access token request.

Facebook Same Window Authentication

I am trying to do Facebook authentication in same window of my web application's login page.
I am using following code when user clicked login button to go to authentication page.
function loginUsingOAUTH()
{
top.location = 'https://graph.facebook.com/oauth/authorize?client_id=839846246064537&scope=email&redirect_uri=http://www.olcayertas.com/testqa/result.html';
}
1) After authentication Facebook redirects me to my redirect url and returns a parameter "code".
At this point I want to access Facebook user information but I don't know how to do that.
What is this "code" parameter for?
2) Is there any other way to access user information?
3) Do you have any other advice facebook authentication with same window login?
Thank you in advance for your help
When you get the code you should make a server side request to get an access token and than pass the access token to user. It is explained in Facebook Developer page:
Exchanging code for an access token
To get an access token, make an HTTP GET request to the following
OAuth endpoint:
GET https://graph.facebook.com/v2.3/oauth/access_token?
client_id={app-id}
&redirect_uri={redirect-uri}
&client_secret={app-secret}
&code={code-parameter}
This endpoint has some required parameters:
client_id. Your app's IDs
redirect_uri. This argument is required and must be the same as the original request_uri that you used when starting the OAuth login
process.
client_secret. Your unique app secret, shown on the App Dashboard. This app secret should never be included in client-side code or in
binaries that could be decompiled. It is extremely important that it
remains completely secret as it is the core of the security of your
app and all the people using it.
code. The parameter received from the Login Dialog redirect above.
Response
The response you will receive from this endpoint will be returned in
JSON format and, if successful, is
{“access_token”: <access-token>, “token_type”:<type>, “expires_in”:<seconds-til-expiration>}
If it is not successful, you will receive an explanatory error
message.

Token based authorization in nodejs/ExpressJs and Angular(Single Page Application)

In my application,while registering the users i am saving username,password and jwt generated token with these fields in MONGO DB.When user tries to login with correct credentials then i will send the response with stored token.Then at client side(In my controller) i am using the localstorage to store the token so that i can send the same token for each and every request sent by the client.But I found some issues regarding this procedure:
I am generating same token for one user every time.So if any third person is able to get the token then he can access the restricted page.
Am i wasting space in db by storing the generated token in MONGODB
Can Anyone access the token stored in localstorage other than the user.
for each and every request in my single page application,I am again querying mongodb to get the token for that user and validating.Here,I am checking both client side and server side.
I am using jwt to generate tokens,Node,Express,Mongoose in my application
Am i following the good procedure.If not,can you please provide the solution for my approach or any new approach.
I have searched many sites for token based authorization and session based authorization,But nothing worked for me.
Note:I am beginner for Nodejs,AngularjS
You should store token in advanced key-value cache tool like: Redis
That would improve performance remarkably.
You will get token from database for 1st time then it should be stored in Redis. I used to set token as key and username as value. Next request , the token will be given from cache. with Redis you can set expire for token.
When a user registers, you would need to generate a JWT like you're doing now. That's OK. You don't need to save it to the database however. You didn't ask but I assume that the password should not be stored in clear text. You can use something bcrypt to encrypt before saving it to the database.
When user tries to login with correct credentials then i will send the response with stored token
Yes, that's correct way to do.
Then at client side(In my controller) i am using the localstorage to store the token so that i can send the same token for each and every request sent by the client.
Yes, on the client side, you can save the JWT to local storage and send it in subsequent requests to the server.
Now your bullet points:
So that you won't have the same JWT each time, you can include an "exp" claim in the payload (I'm assuming you're using something like jwt-simple to generate a JWT). Something like:
var payload = {
sub: account.username,
exp: moment().add(10, 'days').unix()
};
var token = jwt.encode(payload, "secret");
You don't need to store the JWTs in the database. In some cases, the token issuers (the authorization servers) are not the same as the resource servers. The resource servers only receives the JWTs in a request but there's no way for the resource servers to touch the database used by the authorization servers. Side note: If you eventually need to support refresh tokens, i.e. the JWTs that you hand to the clients will need to eventually expire, then you can store the refresh token in a database. Refresh tokens are not the same as JWTs (access tokens). The complexity to support refresh tokens will increase.
Local storage is not where you store passwords, but it can be used to store JWTs. For that very reason, a JWT must and should expire after a certain time.
Not sure what you mean by saying you check both client side and server side. When the client needs to access a resource (again it's fair to assume that the resource server might not be the same as the authorization server), the only thing that the resource server is passed is the JWT. Anyone can decode a JWT. For example, try to paste your JWT on this site http://jwt.io/. That's why a JWT should not contain any sensitive data. But if the resource server knows the secret that the authorization server uses when it encode the JWT, the resource server can verify the signature. Back to your third bullet, that's why it's OK to store the JWT in local storage of the client.
Update I'm updating this to answer to some of your questions in the comment box.
User clicks on 'Login' button triggers the Angular controller to post a request to the server, something like:
$http.post(url, {
username: $scope.username,
password: $scope.password
}).success(function(res) { ... })
Server receives the POST request, it checks username/password, then it generates a JWT, and sends back to the browser. Note that it does not have to save the JWT to the database. The code would be something like
var payload = {
sub: account.username,
exp: moment().add(10, 'days').unix()
};
var token = jwt.encode(payload, "secret");
res.status(200).json({
token: token
});
Back on the client side, in the success() callback above, now you can save the JWT in local storage:
.success(function(res) { $window.localStorage.setItem('accessJWT', res.token) })
The user is now authenticated. Now when user wants to access a protected resource, user don't have to provide username/password. With the JWT which can be retrieved from local storage, the client can now put the JWT in the Authorization header of the request using the bearer scheme, and sends the request to the server. In code, it would like:
headers.Authorization = 'Bearer ' + token;
The server receives the request. Again, this server receiving this request does not have to be the same as the server which generates the JWT above. The 2 servers can be in 2 different continents. Even if you save the JWT above, that does not do any good to this server which can not access the database where the JWT is stored. But this server can pull out the bearer token from the header of the request, validates the token and carries on with the normal tasks.
Hope this helps.
You do not want to store the JWT in mongoose because it appears in headers when logging in. You first generate a token then hash it using a module like crypto.
There are different ways to do this and they all use Passport which handles the tokens. Here's an example project Satellizer
I would recommend you generate the angular-fullstack project. Then go through the server/auth folder and the client/account folder. You will see how to securely handle authentication in a MEAN based app.

XMLHttpRequest not caching basic HTTP auth in firefox

I am trying to authorize a user with basic HTTP auth with an XMLHttpRequest object in Firefox 25 in a custom extension.
The flow is like so:
hit URL that is HTTP basic auth protected, authorize using either xml.open('GET', url, true, username, password) or xml.setRequestHeaders('Authorization', 'Basic someBASE64encodedSTRING==').
be redirected to another, arbitrary, non-HTTP-basic-protected URL.
be redirected back to my protected URL from step 1. Between step 1 and 3, the basic auth is lost, and on step (3) the user is again presented with the basic HTTP auth modal.
Is there a way to force the browser (specifically firefox) to cache the authorization?
In Chrome I was able to solve this issue using chrome.webRequest.onAuthRequired listener: https://gist.github.com/Lordnibbler/2b616adfa4662ece5095
As HTTP is stateless protocol...
in Step 1) once you authenticate - web server should return you "session id" - unique string by which web server knows, that you were authenticated. You should save that "session id" to a cookie.
2) maybe step 2 returns session id - also possibility. Otherwise its irrelevant.
3) make sure that you send "session id" with your requests - should work
p.s. I just popped here randomly... I have never developed any firefox extension.

Categories

Resources