oauth2-proxy/assets/js/9f61b932.3467cc4b.js

1 line
11 KiB
JavaScript

"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[8583],{3905:function(e,t,n){n.d(t,{Zo:function(){return c},kt:function(){return k}});var i=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function s(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function a(e,t){if(null==e)return{};var n,i,o=function(e,t){if(null==e)return{};var n,i,o={},r=Object.keys(e);for(i=0;i<r.length;i++)n=r[i],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i<r.length;i++)n=r[i],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=i.createContext({}),u=function(e){var t=i.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},c=function(e){var t=u(e.components);return i.createElement(l.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},h=i.forwardRef((function(e,t){var n=e.components,o=e.mdxType,r=e.originalType,l=e.parentName,c=a(e,["components","mdxType","originalType","parentName"]),d=u(n),h=o,k=d["".concat(l,".").concat(h)]||d[h]||p[h]||r;return n?i.createElement(k,s(s({ref:t},c),{},{components:n})):i.createElement(k,s({ref:t},c))}));function k(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=n.length,s=new Array(r);s[0]=h;var a={};for(var l in t)hasOwnProperty.call(t,l)&&(a[l]=t[l]);a.originalType=e,a[d]="string"==typeof e?e:o,s[1]=a;for(var u=2;u<r;u++)s[u]=n[u];return i.createElement.apply(null,s)}return i.createElement.apply(null,n)}h.displayName="MDXCreateElement"},831:function(e,t,n){n.r(t),n.d(t,{assets:function(){return c},contentTitle:function(){return l},default:function(){return k},frontMatter:function(){return a},metadata:function(){return u},toc:function(){return d}});var i=n(7462),o=n(3366),r=(n(7294),n(3905)),s=["components"],a={id:"session_storage",title:"Session Storage"},l=void 0,u={unversionedId:"configuration/session_storage",id:"configuration/session_storage",title:"Session Storage",description:"Sessions allow a user's authentication to be tracked between multiple HTTP",source:"@site/docs/configuration/sessions.md",sourceDirName:"configuration",slug:"/configuration/session_storage",permalink:"/oauth2-proxy/docs/next/configuration/session_storage",draft:!1,editUrl:"https://github.com/oauth2-proxy/oauth2-proxy/edit/master/docs/docs/configuration/sessions.md",tags:[],version:"current",frontMatter:{id:"session_storage",title:"Session Storage"},sidebar:"docs",previous:{title:"BitBucket",permalink:"/oauth2-proxy/docs/next/configuration/providers/bitbucket"},next:{title:"TLS Configuration",permalink:"/oauth2-proxy/docs/next/configuration/tls"}},c={},d=[{value:"Cookie Storage",id:"cookie-storage",level:3},{value:"Redis Storage",id:"redis-storage",level:3},{value:"Usage",id:"usage",level:4}],p={toc:d},h="wrapper";function k(e){var t=e.components,n=(0,o.Z)(e,s);return(0,r.kt)(h,(0,i.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"Sessions allow a user's authentication to be tracked between multiple HTTP\nrequests to a service."),(0,r.kt)("p",null,"The OAuth2 Proxy uses a Cookie to track user sessions and will store the session\ndata in one of the available session storage backends."),(0,r.kt)("p",null,"At present the available backends are (as passed to ",(0,r.kt)("inlineCode",{parentName:"p"},"--session-store-type"),"):"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#cookie-storage"},"cookie")," (default)"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#redis-storage"},"redis"))),(0,r.kt)("h3",{id:"cookie-storage"},"Cookie Storage"),(0,r.kt)("p",null,"The Cookie storage backend is the default backend implementation and has\nbeen used in the OAuth2 Proxy historically."),(0,r.kt)("p",null,"With the Cookie storage backend, all session information is stored in client\nside cookies and transferred with each and every request."),(0,r.kt)("p",null,"The following should be known when using this implementation:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Since all state is stored client side, this storage backend means that the OAuth2 Proxy is completely stateless"),(0,r.kt)("li",{parentName:"ul"},"Cookies are signed server side to prevent modification client-side"),(0,r.kt)("li",{parentName:"ul"},"It is mandatory to set a ",(0,r.kt)("inlineCode",{parentName:"li"},"cookie-secret")," which will ensure data is encrypted within the cookie data."),(0,r.kt)("li",{parentName:"ul"},"Since multiple requests can be made concurrently to the OAuth2 Proxy, this session implementation\ncannot lock sessions and while updating and refreshing sessions, there can be conflicts which force\nusers to re-authenticate")),(0,r.kt)("h3",{id:"redis-storage"},"Redis Storage"),(0,r.kt)("p",null,"The Redis Storage backend stores encrypted sessions in redis. Instead of sending all the information\nback the client for storage, as in the ",(0,r.kt)("a",{parentName:"p",href:"#cookie-storage"},"Cookie storage"),", a ticket is sent back\nto the user as the cookie value instead."),(0,r.kt)("p",null,"A ticket is composed as the following:"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"{CookieName}-{ticketID}.{secret}")),(0,r.kt)("p",null,"Where:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"The ",(0,r.kt)("inlineCode",{parentName:"li"},"CookieName")," is the OAuth2 cookie name (_oauth2_proxy by default)"),(0,r.kt)("li",{parentName:"ul"},"The ",(0,r.kt)("inlineCode",{parentName:"li"},"ticketID")," is a 128-bit random number, hex-encoded"),(0,r.kt)("li",{parentName:"ul"},"The ",(0,r.kt)("inlineCode",{parentName:"li"},"secret")," is a 128-bit random number, base64url encoded (no padding). The secret is unique for every session."),(0,r.kt)("li",{parentName:"ul"},"The pair of ",(0,r.kt)("inlineCode",{parentName:"li"},"{CookieName}-{ticketID}")," comprises a ticket handle, and thus, the redis key\nto which the session is stored. The encoded session is encrypted with the secret and stored\nin redis via the ",(0,r.kt)("inlineCode",{parentName:"li"},"SETEX")," command.")),(0,r.kt)("p",null,"Encrypting every session uniquely protects the refresh/access/id tokens stored in the session from\ndisclosure. Additionally, the browser only has to send a short Cookie with every request and not the whole JWT,\nwhich can get quite big."),(0,r.kt)("p",null,"Two settings are used to configure the OAuth2 Proxy cookie lifetime:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"--cookie-refresh duration refresh the cookie after this duration; 0 to disable\n--cookie-expire duration expire timeframe for cookie 168h0m0s\n")),(0,r.kt)("p",null,'The "cookie-expire" value should be equal to the lifetime of the Refresh-Token that is issued by the OAuth2 authorization server.\nIf it expires earlier and is deleted by the browser, OAuth2 Proxy cannot find the stored Refresh-Tokens in Redis and thus cannot start\nthe refresh flow to get new Access-Tokens. If it is longer, it might be that the old Refresh-Token will be found in Redis but has already\nexpired.'),(0,r.kt)("p",null,'The "cookie-refresh" value controls when OAuth2 Proxy tries to refresh an Access-Token. If it is set to "0", the\nAccess-Token will never be refreshed, even it is already expired and there would be a valid Refresh-Token in the\navailable. If set, OAuth2 Proxy will refresh the Access-Token after this many seconds even if it is still valid.\nOf course, it will also be refreshed after it has expired, as long as a Refresh Token is available.'),(0,r.kt)("p",null,'Caveat: It can happen that the Access-Token is valid for e.g. "1m" and a request happens after exactly "59s".\nIt would pass OAuth2 Proxy and be forwarded to the backend but is just expired when the backend tries to validate\nit. This is especially relevant if the backend uses the JWT to make requests to other backends.\nFor this reason, it\'s advised to set the cookie-refresh a couple of seconds less than the Access-Token lifespan.'),(0,r.kt)("p",null,"Recommended settings:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"cookie_refresh := Access-Token lifespan - 1m"),(0,r.kt)("li",{parentName:"ul"},"cookie_expire := Refresh-Token lifespan (i.e. Keycloak client_session_idle)")),(0,r.kt)("h4",{id:"usage"},"Usage"),(0,r.kt)("p",null,"When using the redis store, specify ",(0,r.kt)("inlineCode",{parentName:"p"},"--session-store-type=redis")," as well as the Redis connection URL, via\n",(0,r.kt)("inlineCode",{parentName:"p"},"--redis-connection-url=redis://host[:port][/db-number]"),"."),(0,r.kt)("p",null,"You may also configure the store for Redis Sentinel. In this case, you will want to use the\n",(0,r.kt)("inlineCode",{parentName:"p"},"--redis-use-sentinel=true")," flag, as well as configure the flags ",(0,r.kt)("inlineCode",{parentName:"p"},"--redis-sentinel-master-name"),"\nand ",(0,r.kt)("inlineCode",{parentName:"p"},"--redis-sentinel-connection-urls")," appropriately."),(0,r.kt)("p",null,"Redis Cluster is available to be the backend store as well. To leverage it, you will need to set the\n",(0,r.kt)("inlineCode",{parentName:"p"},"--redis-use-cluster=true")," flag, and configure the flags ",(0,r.kt)("inlineCode",{parentName:"p"},"--redis-cluster-connection-urls")," appropriately."),(0,r.kt)("p",null,"Note that flags ",(0,r.kt)("inlineCode",{parentName:"p"},"--redis-use-sentinel=true")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"--redis-use-cluster=true")," are mutually exclusive."),(0,r.kt)("p",null,"Note, if Redis timeout option is set to non-zero, the ",(0,r.kt)("inlineCode",{parentName:"p"},"--redis-connection-idle-timeout"),"\nmust be less than ",(0,r.kt)("a",{parentName:"p",href:"https://redis.io/docs/reference/clients/#client-timeouts"},"Redis timeout option"),". For example: if either redis.conf includes\n",(0,r.kt)("inlineCode",{parentName:"p"},"timeout 15")," or using ",(0,r.kt)("inlineCode",{parentName:"p"},"CONFIG SET timeout 15")," the ",(0,r.kt)("inlineCode",{parentName:"p"},"--redis-connection-idle-timeout")," must be at least ",(0,r.kt)("inlineCode",{parentName:"p"},"--redis-connection-idle-timeout=14")))}k.isMDXComponent=!0}}]);