Testing parser for oauth2 implicit grant access_token in javascript - javascript

I'm writing angular application that uses implicit grant oauth strategy. If I don't have valid access token in my cookies I am redirected to web interface of authentication server, input my credentials and get redirected to my site with access token in the url. My system parses it and writes down into cookies.
Currently I faced question of unit testing this parse function that consumes the url and returns access token object. Can't think the good way, so writing here:
1. How do you approach unit testing (so I can't make direct request to working oauth server) a function that parses the access token from authentication server?
2. How do you build url params with access token? Will it be secure if I copy current access token and use it in test data?
3. Are there libraries that can aid creation of mock access token object?

You could breakout "just enough" OAuth, like the service linked below. This will give you a super-basic OAuth provider, but is really geared to "integration testing" scenarios (depending on where you draw the lines on these things).
If you want to be a unit-testing purist/zealot, then you could fork this into your app's unit test code.
https://github.com/zalando-stups/mocks/tree/master/oauth2-provider
In lieu of a great answer, here's one to get you out of a hole :)

After approaching authors of my oAuth authentification service I've got insight on the data the server was sending me in case of successful authentication. In my case the response from oAuth server has the following form:
header // encoded algorithm for has creation
access token // base64 encoded object
hash // of the 3 previous items done using algorithm specified in the header.
It has the following structure: header.access_token.hash
My fear for security breach was concerned about putting correct data (that I can get from browser) into the test files. But as it turns out the token will not be valid without correct hash. The hashing of the token data is done in server side using private key, so if I change the hash the token will become obsolete.
As my token-parsing-function that I wanted to check uses only the access_token part of the request, I've changed the header and hash parts and also encoded other user name for sake of testing purposes.
So this is the resolution of my current problem. Hope this will help somebody.

Related

NextAuth - mocking OneLogin flow

I'm trying to setup a OneLogin mocked service locally using WireMock. So far so good, I was able to mock most of the OAuth OneLogin flow but I can't manage to solve the last part in order to get it working properly...
Whenever I submit credentials on my Mocked OneLogin page and it redirects me back to the application I get error: RPError: failed to validate JWT signature. From the debugging I discovered that the problem is in the mocked OneLogin server on the "jwks_uri": "http://localhost:27442/oidc/2/certs" endpoint. Seems the last part of NextAuth verification which is using jose..compactVerify(jwt, key instanceof Uint8Array ? key : key.keyObject) doesn't match what I've mocked thus not allowing me to proceed with mocked login.
Does anyone know what should the /oidc/2/certs endpoint return to match generated mocked token??
How should the JWT and return value of oidc/2/certs look like to be approved.
I generated JWT on https://jwt.io/
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTY2NjAwMDgwMCwiZXhwIjoxNjY4Njc5MjAwLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjI3NDQyL29pZGMvMiIsImF1ZCI6InNvbWUtY2xpZW50LWlkIn0.QLqLlhoZi7JnqTAYibPkIFPvmC88t4Z7AbUspSX8ENbEnK0NXV_hTxAXLA3-V7TjuIWlrJOvOT7BrHP3N39XV0Vb5pw_X4OY48ce9JQR46x5v3YeU4wgm48sWCIkwRVNDGV0_oF1Pr2Qa4egAVDzLDxtoqrgV4W_wjOI-jxv2r0NWeNvgsSH68PC0qTcgfuLG_k1Sf61CBS-_DKHGznD9gdHc3xJM2Rh3FLQQ5-JHVlE0nB0If8Gx-Q5_cI2VQaDwj-x4VO9qzE2o1zes41NgyP1D85TODegPN6lNvpLMyexIBwl5LYP0WnpW9ZDKziUqVLkuJ4LTnl5jg9ZsbXQ2Q
and looking at onelogin docs I found this https://acme.onelogin.com/oidc/2/certs
How can I match above to be verified successfully? I basically want an infinite JWT (RS256 alg) token that will be verified mitigating OneLogin flow in development environment
After fighting with this for several days I found a solution.
I had to Generate JWT token with appropriate header and payload values on https://jwt.io/#debugger-io then copy public key and generate JWK with it on
https://russelldavies.github.io/jwk-creator/

How to use one JWT token to sign a second JWT token?

The Scenario: A web-app user wants to create an authorised view of a private asset. The user has authenticated and has a jwt token. The app wants to make a fresh secondary jwt token, which can be verified as having been created with the original token.
FYI: My use case is signing a url - adding the second jwt token to the url, to allow controlled public viewing of the private asset.
How should the app do that?
E.g. is there a recommended way to set secret and alg for this 2nd token?
In theory, to use one jwt to sign another, you'd use the HS256 algorithm, with the first jwt as the secret. In practice, this approach leads to a couple of issues, outlined below:
Firstly, only the server and the original token-holder will be able to verify the authenticity of this token, and in order for the server to perform verification, you'll need to persist the original token somewhere. This is outside the scope of your question, but it does begin to complicate the implementation, since now both tokens mush share a lifespan, and the original token needs to be available wherever the second token might be used. That might not be an issue for your use case but it does somewhat limit portability, as well as future-proofing if, for example, another party needed to verify the token (such a use case can be achieved without too much overhead by using RS256 and asymmetric keys instead of the HS256/symmetric key method).
Secondly, JWTs are commonly transient values with short lifespan. This is usually due to the nature of their use: since they are shared between a client and server, they are not strictly speaking "secret" values, and the longer they live, the greater the chance that they may have been compromised. In using them as secret material for other tokens, you now require a longer lifespan for those tokens, and you are potentially introducing a security vulnerability wherein the "secondary" tokens could be spoofed by an attacker who gets their hands on one of these "primary" tokens. In order mitigate this specific threat, secret material should be something that is not transmitted over the network.
Perhaps you might consider using the same token generation procedure (same algorithm & secret) for both tokens, and simply include an identifier for the "issuer" (a unique identifier for the user who holds the original token) as part of the second token. Using this method, you don't need to worry about which verification process to use for a given token (since it's now the same for both), nor do you have to worry about token lifespan or key spoofing through a stolen token.
I think the best answer is You shouldn't, at least not on the client side. If you mean your back-end is node or something, you could do something like this.
Have the client make an authenticated request to give me access to resource x.
The server can at that point take any information from the original token to create a new JWT token, with the data below.
Sign the jwt serverside with whatever method you prefer (I would always use RS256, with certificate).
Respond the the client with, you can access the resource at protected/resource_x?key=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJodHRwczovL3lvdXIud2ViLnNpdGUvcHJvdGVjdGV4L3Jlc291cmNlX3giLCJpc3MiOiJodHRwczovL3lvdXIud2ViLnNpdGUiLCJleHAiOjE2MTU4MTIyOTQ5ODMsInNjcCI6InByaXZhdGVfcmVzb3VyY2UiLCJzdWIiOiJvcmlnaW5hbC11c2VyLWlkLWZyb20tY2xpZW50LXRva2VuIn0.cga9CQ1IqUwzBRgYM3vlUN0g37yJWZREQQEExV29UWs
Your jwt can contain the following information:
{
"aud": "https://your.web.site/protectex/resource_x",
"iss": "https://your.web.site",
"exp": 1615812294983,
"scp": "private_resource",
"sub": "original-user-id-from-client-token"
}

Why jwt token shows payload even i didn't provide secret (Signature ) in Jwt.io?

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOjIsImlhdCI6MTU2ODY1NjI1OX0.E2TNtWjqyPC-4myEom6leLJgE96ZlQOq0-mcBr3p5QU
If we place the token which is generated from my code using JsonWebToken in Jwt.io site it is decoded immediately even though I did not provide the secret to validate.
I don't know why it shows. Can somebody explain the reason for that?
--Then what is purpose of SECRET in Jwt??
I think you're getting a little confused between encryption and signing.
A JSON web token is not encryped, it's just base64 encoded meaning it's very simple to decode and view by anyone.
It is however signed, which means it has a hash generated based on all the information within it and a secret key. Only those with a secret key (for symmetric hashing) or the public key (for asymmetric hashing) are able to confirm that the token has been hashed correctly, and only the provider of the key (who owns the secret token) is able to create valid hashes.
What this does, is gives you confidence that the token has been created by the person/service you think it was created from, preventing impersonation etc and therefore allows you to trust the claims that have been made within the token. If that hash were invalid for any reason you would immediately reject the token on the basis it's most likely forged.
Note that as #FlorentMorselli mentioned there is such a think as an encrypted token called a JWE.

Securing REST API calls with client-side token

I have a node.js REST API and I want to restrict POST/PUT/DELETE calls to a predefined list of "sources" (web applications which I do not own the code).
The only way I see to achieve this is to put a token on the client-side (something like Google Analytics in JS files) but I have no idea how to secure this since the token will be accessible in the static files.
What strategy should I use ? JWT and OAuth2 seem not indicated since it requires first user authentication, but what I want to authenticate is not user but webapps.
Your question is slightly unclear. You could mean either (a) that you want to strongly encourage the user to use the app and prevent other code from maliciously making your user perform an action, or (b) that you want to absolutely prevent your user from using other code to access your server.
The first option is possible, and indeed a very good idea. The second is impossible, based on the way the Internet works.
First, the impossibility. Essentially, client-side code is there to make life easier for your client. The real work will always be done on the server side -- even if this only means validating data and storing it in the database. Your client will always be able to see all the HTTP requests that they send: that's the way HTTP works. You can't hide the information from them. Even if you generate tokens dynamically (see below), you can't prevent them from using them elsewhere. They can always build a custom HTTP request, which means ultimately that they can, if they really, really want, abandon your app altogether. Think of your client-side code as merely making it easier for them to perform HTTP requests and abandon any idea of preventing them "doing it wrong"!
The much better option is CSRF protection, which gives the best possible protection to both your server and the client. This means sending a generated token to your client when they first log on and verifying it (either by looking it up or decrypting it) when they send it on every request. This is the basis of JWT, which is a beautiful implementation of a fairly old system of verification.
In the end your API is public, since any random website visitor will have to be able to interact with the API. Even if you use tokens to restrict access somewhat, those tokens by definition will have to be public as well. Even regularly expiring and renewing the tokens (e.g. through a backend API, or by including a nonce algorithm) won't help, since those new tokens will again be publicly visible on the 3rd party's website where anyone can fetch one.
CSRF protection can help a little to avoid cross-site abuse within browsers, but is ultimately pointless for the purpose of preventing someone to write an API scraper or such.
The best you can do is use the tokens to identify individual site owners you granted access to, vigilantly monitor your API use, invalidate tokens when you think you're seeing them abused and contact the site owners about securing their tokens better somehow (which they'll have the same problem doing, but at least you have someone to blame cough cough).
You can use hmac to secure this :
Each client has a unique couple of key public/private (for example "public" and "private").
When client send request, he has to send a nonce + his user public key + the hmac of nonce+public key with his private key.
When server handle request, the server retrieve the client according to his public key, get the secret key of the user, then verify the signature.
Client, sample call on /api
var nonce = "randomstring";
var pk = "aaa";
var sk = "bbb";
var string = "pk="+pk+"&nonce="+nonce;
var crypto = require('crypto');
var hmac = crypto.createHmac('sha512', sk).update(string).digest('hex');
// send this payload in your request in get, put, post, ....
var payload = string+"&hmac="+hmac;
request.post({uri:"website.com/api?"+payload}, ....
And
Server side, security check
var nonce = req.query.nonce;
var pk = req.query.pk;
var hmac = req.query.hmac;
// retrieve user and his sk according to pk
var sk = getUser(pk).sk
// rebuild payload string
var string = "pk="+pk+"&nonce="+nonce;
var crypto = require('crypto');
var hmac_check = crypto.createHmac('sha512', sk).update(string).digest('hex');
if(hmac_check === hmac) { // request valid }else{ // invalid request }

Authentication for a SPA and a node.js server

I have a very simple node.js app built on express which has been handling authentication using a session memory store. Basically a user logs in by:
app.post('/sessions', function(req, res) {
// check username/password and if valid set authenticated to true
if (authenticated){
req.session.user = req.body.username;
} ...
});
Then in each call from the browser a requiresLogin middleware function is called which checks to see if that user property on the session has been set.
I'm now transitioning the app to basically just provide a service that may or may not be consumed in the browser, so instead of using cookies/sessions, I'm considering changing the system so that one would post to /getToken (instead of /sessions) which would return a temporary random token associated with a user's account that could then be used for a period of time to access the service. Using the service would then require a valid token to be included in each call. (I assume this would be better than passing the username/password each time so that the password would not have to be stored in memory on the client's computer after the call to get token?)
Would such a system basically be just as secure as the above current system or Is there a much more standard/safe way to handle this? What's the standard way to handle something like this?
Thanks in advance for you help!
What you are looking for is called an HMAC and there is a great article here to get ideas on how to implement for your service.
As to whether session based security is more secure than public/private keypairs is widely debated and really depends on the implementation/application. In your case, since you want per request authentication on a public facing API, the HMAC is the way to go.

Categories

Resources