{"_id":"express-deep-link","_rev":"151-33e4491e840d1093fd69ea3d9b2c7938","name":"express-deep-link","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"express-deep-link","version":"1.0.0","keywords":["deep","link","express","middleware"],"author":{"name":"@armw4"},"license":"MIT","_id":"express-deep-link@1.0.0","maintainers":[{"name":"lanetix","email":"engineering@lanetix.com"}],"homepage":"https://github.com/lanetix/express-deep-link","bugs":{"url":"https://github.com/lanetix/express-deep-link/issues"},"dist":{"shasum":"15d081eb309f395f2365feaf9b45d2967d453867","tarball":"https://registry.npmjs.org/express-deep-link/-/express-deep-link-1.0.0.tgz","integrity":"sha512-joRPFFF5iC39fcHQ3G1JhwElPVvYHodTaOkTRutSSLViiOF4YXTPmee0qiWMcyTuaAPZGICkWCF5gCmDw7T9pA==","signatures":[{"sig":"MEYCIQDxNNdnI9i1QmUvRWpApc6NJUnagugWcO+92hPNvIvelQIhALaYwibCLej54hlHLan9gbELGnmODt6YaJQnB0cpHv5l","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"index.js","_from":".","_shasum":"15d081eb309f395f2365feaf9b45d2967d453867","gitHead":"474f3ac2d33ef786ad3136975e449cab19099fd1","scripts":{"test":"gulp test"},"_npmUser":{"name":"lanetix","email":"engineering@lanetix.com"},"repository":{"url":"git+https://github.com/%3Alanetix/express-deep-link.git","type":"git"},"_npmVersion":"2.9.0","description":"Provides deep linking capabilities via express middleware.","directories":{},"_nodeVersion":"1.8.2","dependencies":{"gulp":"3.8.11","lodash":"3.9.3"},"devDependencies":{"sinon":"1.14.1","should":"6.0.3","gulp-mocha":"2.1.1"}}},"time":{"created":"2015-06-15T18:52:52.379Z","modified":"2026-08-03T11:04:16.206Z","1.0.0":"2015-06-15T18:52:52.379Z"},"bugs":{"url":"https://github.com/lanetix/express-deep-link/issues"},"author":{"name":"@armw4"},"license":"MIT","homepage":"https://github.com/lanetix/express-deep-link","keywords":["deep","link","express","middleware"],"repository":{"url":"git+https://github.com/%3Alanetix/express-deep-link.git","type":"git"},"description":"Provides deep linking capabilities via express middleware.","maintainers":[{"email":"systems@lanetix.com","name":"lanetix-system"},{"email":"jyothiss@qburst.com","name":"jyothis-qb"},{"email":"manu.kodiyan@winmore.app","name":"manu-kodiyan-winmore"},{"email":"ie_winmore_notify@deloitte.com","name":"dnm-winmore"},{"email":"mkdyanugk@gmail.com","name":"mkdyanugk"},{"email":"vigneshk@qburst.com","name":"vigneshk7"},{"email":"aswanth@qburst.com","name":"aswanth"},{"email":"sajith@qburst.com","name":"sajith.qb"},{"email":"dhiluraj@qburst.com","name":"dhiluraj-qburst"},{"email":"rohith.menon@qburst.com","name":"cdrohithmqb"},{"email":"arjun.venugopal@qburst.com","name":"arjunqb"},{"email":"renjith.ramaswamy@qburst.com","name":"renjith_ram_qburst"},{"email":"sidharth.n@qburst.com","name":"sidharth.n"},{"email":"rahul.bharadwaj@winmore.app","name":"rahulbharadwaj"},{"email":"jasif.shameem@winmore.app","name":"jasif-wm"},{"email":"arpit.shrivastava@winmore.app","name":"arpit1024"},{"email":"showvhick.nath@winmore.app","name":"showvhick-winmore"},{"email":"umesh.sahu@winmore.io","name":"umeshsahu32"},{"email":"karthik.chandran@qburst.com","name":"kaarthikchandran"},{"email":"siddlinga.reddy@winmore.io","name":"siddling"},{"email":"manoj.k@winmore.io","name":"mkdyanugk7"},{"email":"souraj.pal@winmore.io","name":"sourajpal"},{"email":"karan.parmar@winmore.io","name":"karan_winmore"},{"email":"yash.patel@winmore.io","name":"yash.patel.winmore"},{"email":"divyansh@winmore.app","name":"divyansh-winmore"},{"email":"ravi.sah@winmore.app","name":"ravi.sah"},{"email":"subham.jaiswal@winmore.app","name":"dev-saj-winmore"}],"readme":"Compatible with [express 4.x](http://expressjs.com/4x/api.html).\n\n## What is Deep Linking?\n\nDeep linking occurs when users access a url of arbitrary depth on your website. As noted on Wikipedia,\nit's the difference between www.my.site.com/ (the root of the website) and www.my.site.com/some-url/of/arbitrary/depth (a deep linked\nurl). Deep linking is a given for public unauthenticated websites. There's nothing special you have to do in order to get it to work.\nHowever, once authentication comes into play, you'll need to know where an unauthenticated user was attempting to go after they've logged\nin to your website:\n\n1. Susie gets a link to your site from Brad (www.your.site.com/some/path/other-than/the-root-url)\n2. Susie clicks on this link\n3. Susie is not authenticated and gets redirected to login and prompted for her credentials\n4. Instead of getting blindly sent to the root of the website (/), Susie is sent to where she was initially attempting to go before she was prompted to login.\n\nThat's the base use case for this middleware. Remember where a user was trying to go prior to logging in, and send them\nback to that place after the fact. Of course if a user just logs into your site and never issued a request while unauthenticated,\nit'll be business as usual.\n\n## Options\n\n### baseUrl - String (Optional)\n\nThe `baseUrl` option is optional and is for validation/security purposes. It will ensure that the value stored inside the return url is not pointing\nto a different website. For example, if your website is hosted on https://www.somedomain.com/, all return urls should begin\nwith this value. That is to say, they should be relative to https://www.somedomain.com/.\n\n```js\nvar deep     = require('express-deep-link');\nvar deepLink = deep({ baseUrl : 'https://my.site.com/blah' });\nvar express  = require('express');\nvar app      = express();\n\napp.use(deepLink);\n```\n\n### cookie - Object (Optional)\n\nThe `cookie` option can be used to override settings for how the return url is persisted as a cookie.\n\n#### cookie.name - String (Optional)\n\nControls the name of the cookie on the response.\n\nDefault - `returnUrl`\n\n```js\nvar deep     = require('express-deep-link');\nvar deepLink = deep({ cookie : { name : 'BLAH' } });\nvar express  = require('express');\nvar app      = express();\n\napp.use(deepLink);\n```\n\n#### cookie.options - Object (Optional)\n\nA hash of options that should conform to that of [`res.cookie`](http://expressjs.com/api.html#res.cookie).\n\nDefault - `{ httpOnly : true }`\n\n```js\nvar deep     = require('express-deep-link');\nvar deepLink = deep({\n  cookie : {\n    options : {\n      domain: '.example.com',\n      path: '/admin',\n      secure: true,\n      expires: new Date(Date.now() + 900000)\n      // httpOnly : true would not be necessary here since\n      // it's apart of the default options\n    }\n  }\n});\nvar express  = require('express');\nvar app      = express();\n\napp.use(deepLink);\n```\n\n### login - Object (Required)\n\nThe `login` option is responsible for logging in an unauthenticated user. It supports both local and remote\nlogin.\n\n**NOTE:** The `login.local` and `login.remote` options are mutually exclusive and you must set ***EXACTLY ONE*** of\nthese options in order to use `deep-link`.\n\n#### login.local - Object (Required if not using login.remote)\n\nInstructs the middleware that the login endpoint is deployed to the same host/website as the target website (the one you'll be deep linking into)\n\n```\nhttps://contoso.com/login\n```\n\nas opposed to a remote host:\n\n```\nhttps://login.contoso.com\n```\n\n##### login.local.path - String (Required if using login.local)\n\nThis is the request path (equivalent to the `req.path` property of an express request) of the local login endpoint.\n**It should always begin with a forward `/`** as [depicted in the express docs](http://expressjs.com/api.html#req.path).\nWhy is this option important? When the path of the current request is equal to this value, `deep-link` will allow the\nrequest to pass through (without a redirect) so as to avoid infinite redirects. `deep-link` should not redirect you to the\nlogin page if you're actually trying to visit the login page...:facepunch:.\n\n```js\nvar deep     = require('express-deep-link');\nvar deepLink = deep({\n  login : {\n    local : {\n      path : '/login'\n    }\n  }\n});\nvar express  = require('express');\nvar app      = express();\n\napp.use(deepLink);\n```\n\n##### Why Does deep link Guard Against Infinite Redirects?\n\nIt's well known that you can use the express router at a very granular level. Enough so that you have absolute control\nover which routes a given middleware or set of middleware will execute for. We contemplated removing the infinite redirect guard from\n`deep-link`. The thought was that developers could take time out to properly configure their middleware as opposed to registering `deep-link`\nto run on every request:\n\n```js\nvar express     = require('express');\nvar deep        = require('express-deep-link');\nvar app         = express();\nvar authRouter  = express.Router();\nvar apiRouter   = express.Router();\nvar loginRouter = express.Router();\nvar auth        = require('./middleware/your-app-auth');\nvar deepLink    = deep({...options...});\n\n// invoked for any requests passed to this router\nauthRouter.use(auth);\nauthRouter.use(deepLink);\n\napiRouter.use(auth);\n\nloginRouter.get('/', function(req, res) {\n  res.render('login');\n});\n\nloginRouter.post('/', function(req, res, next) {\n  // validate the user's credentials and log them\n  // in if successful\n});\n\n// only requests to /ui/* will be sent to our \"router\"\n// the ui router contains both auth and deep linking middleware\napp.use('/ui', authRouter);\n\n// only requests to /api/* will be sent to our \"router\"\n// the api router contains only auth middleware\napp.use('/api', apiRouter);\n\n// only requests to /login/* will be sent to our \"router\"\n// the login router contains NO middleware at all since it should\n// accept unauthenticated requests and no deep linking should ever occur\napp.use('/login', loginRouter);\n```\n\nThe initial argument for this was that if your login endpoint were local to your website, you'd already have to configure your authentication middleware\nnot to authenticate that endpoint (you can't authenticate the route that is responsible for authentication, else users would never be able to authenticate).\nYou'd additionally want to exclude `deep-link` from running on any requests to your API since you'd never deep link to anything accepting or returning JSON payloads.\n@pythonesque made an argument (of which was already entertained) that lots of sites (actually most sites according to him) are not SPAs and still employ\nserver side rendering. In that case, you have only one place to exclude both authentication and `deep-link` (that being login). We concluded that:\n\n1. there's no harm in guarding against infinite redirects\n2. the most convenient option for developers would be to allow them to configure `deep-link` to run for all requests\n\n##### login.local.authenticated - Object (Optional)\n\nControls options related to local authenticated requests.\n\n###### login.local.authenticated.home - Boolean|String (Optional)\n\nThe `login.local.authenticated.home` option is a UX enhancement that prevents authenticated users from being allowed\nto visit the login route (`login.local.path`). When this option is set, authenticated users will get redirected to the\n`/` (root) url when the value of `home` is a `Boolean` (true), or to the value of the `home` option when it is of type\n`String`.\n\n```js\nvar deep     = require('express-deep-link');\nvar deepLink = deep({\n  login : {\n    local : {\n      path : '/login',\n      authenticated : { home : true } // Boolean\n    }\n  }\n});\nvar express  = require('express');\nvar app      = express();\n\napp.use(deepLink);\n```\n\n**OR**\n\n```js\nvar deep     = require('express-deep-link');\nvar deepLink = deep({\n  login : {\n    local : {\n      path : '/login',\n      authenticated : { home : '/home' } // String\n    }\n  }\n});\nvar express  = require('express');\nvar app      = express();\n\napp.use(deepLink);\n```\n\n##### Why Does deep-link Provide this Option?\n\nAgain, developers will most likely want to conveniently configure `deep-link` to run on every request (`*`). A simple middleware could be plugged into\none's Pipeline to perform this very function, but this feature has conveniently been made available free of charge. `deep-link` is already closely tied\nto login and authentication, so might as well....\n\n> \"go hard, or go home.\"\n\n#### login.remote - Object (Required if not using login.local)\n\nInstructs the middleware that the login endpoint is deployed to a remote host/website:\n\n```\nhttps://login.contoso.com)\n```\n\nas opposed to your target website (the one you'll be deep linking into):\n\n```\nhttps://contoso.com/login\n```\n\n##### login.remote.url - String (Required if using login.remote)\n\nThis is the remote endpoint `deep-link` will redirect any unauthenticated requests to. This dffers from the `login.local` option\nas `login.local` does not require redirects and allows a login page to be served from an endpoint relative to the site you're deep linking to.\n\n```js\nvar deep     = require('express-deep-link');\nvar deepLink = deep({\n  login : {\n    remote : {\n      url : 'https://my.secure.site.com'\n    }\n  }\n});\nvar express  = require('express');\nvar app      = express();\n\napp.use(deepLink);\n```\n\n## Where Do I Plug This Into My Pipeline At?\n\nThe expectation is that you'll use this middleware directly after your authentication middleware. Notice how the `authenticated` option is\nsynchronous. The initial thought was that things like promises or async based stuff via `function(err, result)` would need to be accounted for.\nThat would have sucked from a coding perspective. It would have definitely increased the overall complexity of things. Then an epiphany was born:\n\n> \"hey...wait a sec...why don't we just let the authentication middleware handle it's job in the way that it wants.\n..it'll tell us once it's done doing it's job via `next()`...then we can just piggy back off of the results.\"\n\nThat's a much clearer separation of concerns. Authentication middleware can focus on authenticating the current user and bouncing them back to\na login or elsewhere upon failure. Should everything check out, `next()` would be invoked and we can interrogate the results of whatever key said\nauthentication middleware writes to the request. Let's give an example:\n\n```js\n// middleware/authentication.js\n\nvar Authentication = require('../lib/authentication');\n\nfunction(req, res, next) {\n  var token = req.get('X-AUTH-TOKEN');\n\n  if(!token) {\n    /* instead of redirecting to login, give the\n    *  deep linking middleware a chance to store the\n    *  current request url, and THEN redirect to login\n    *  via the login option\n    */\n    next();\n  }\n\n  Authentication\n  .authenticate(token)\n  .then(function(tokenOrWhateverAuthYields) {\n    // we can now pass this in as the authentication option\n    req.user = tokenOrWhateverAuthYields;\n    next();\n  })\n  .error(function(e) {\n    // redirect to login since they gave us a bad token\n  });\n}\n```\n\n```js\n// app.js\n\nvar authentication = require('./middleware/authentication')();\nvar deep           = require('express-deep-link');\nvar express        = require('express');\n\nvar deepLink = deep({\n  authenticated : function() { return req.user; },\n  login         : 'https://secure.login.com'\n});\n\nvar app = express();\n\n// when authentication calls next(), req.user will be populated,\n// and if it's not, deep-link will cache the current url and redirect to login\napp.use(authentication);\napp.use(deepLink);\n```\n\n## The Ultimate Edge Case\n\n1. your login page is local to your target website (`login.local` option)\n2. your login page is served to the browser (`deep-link` is smart enough to prevent an infinite redirect)\n3. your login page requests static assets (images/JavaScript, etc.) after it's been served\n4. `deep-link` intercepts the first request to a static asset\n5. `deep-link` sees that the request is unauthenticated (in the same way it was when the login route was requested)\n6. `deep-link` stores the request to the static asset as the return url\n7. `deep-link` redirects back to the login route\n8. asset not downloaded\n\nThe skinny on this:\n\nFor the potentially small subset of folks that decide not to in-line the assets required for login (such that they\ndon't trigger additional round trips to the server), or decide not to host those assets on a CDN (again such that\nthey don't trigger an additional GET request to the local server), these individuals would already have to exclude authentication for\nsaid assets. This means you already have to be thinking about what middleware should run for a given request.\nWe trust that based on this, you're adequately equipped to configure middleware to conform to your expectations.\n\nWill you be using a CDN in development (in the event that you used one in production under this scenario)? Highly\nunlikely. That being said, you'd be subject to infinite redirects in development if you didn't properly scope your\nlocal login assets to a given folder. However, at a minimum you'd still have to disable authentication for your local login\nassets in development mode. Put simply, you’re already used to thinking outside of the box when it comes to configuring your middleware.\nIn conclusion, there's a limit to how much functionality `deep-link` can provide out of the box. `deep-link` will attempt do the most sensible thing it can\nfor any condition that it can trivially detect and naturally support (i.e. the `login.local.authenticated.home` option). There comes a point where one\nmust have basic knowledge of how middleware work relative to one another and the potential ramifications of a given configuration.\n\n## Beware Thy Hash (#)\n\nIf you're attempting to deep link to a url like http://my.site.com/accounts/#/new (as you would in a SPA), your browser will truncate all characters after\nthe # (hash) before issuing a request which would result in a request to http://my.site.com/accounts. Keep this in mind when using a UI framework such as Angular.\nAngular for example has the concept of HTML 5 Mode (pretty urls that don't contain a #). You'd want to configure your app as such (Angular is smart enough to downgrade\nto # based urls if clients load your app in a legacy browser...best of both :earth_americas:s).\n\n## Why a Cookie vs the Query String?\n\nYou've probably witnessed some sites do the https://www.my.site.com?rUrl=someuriencodedreturnurl thing right?\n\n```\n// example from Google....they chose not to uri encode their return url\nhttps://accounts.google.com/ServiceLogin?hl=en&continue=https://www.google.com/\n```\n\nWe could certainly implement `deep-link` to do the same, but the cookie based approach is much easier on the eyes (doesn't pollute the query sting) and not as\ntrivial to tamper with (the motive for the `baseUrl` option). Maybe a `strategy` option of some sort could be introduced to let you pick which storage mechanism\nyou'd like to use for persisting the url (`cookie`, `query-string`). To be continued...\n\n## Tests\n\n```shell\nnpm install -g gulp\n\ngulp test\n```\n","readmeFilename":"README.md"}