text: (window.webpackJsonp=window.webpackJsonp||[]).push([[13],{153:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return r})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return b}));var i=n(1),a=n(9),o=(n(0),n(199)),r={id:"advanced",title:"Advanced Topics"},c={id:"advanced",title:"Advanced Topics",description:"This guide aims to help setting up a production system with ORY Hydra.",source:"@site/docs/advanced.md",permalink:"/hydra/docs/next/advanced",editUrl:"https://github.com/docs/hydra/edit/master/docs/docs/advanced.md",version:"next",lastUpdatedBy:"hackerman",lastUpdatedAt:1586178985,sidebar:"docs",previous:{title:"Debugging",permalink:"/hydra/docs/next/debugging"},next:{title:"Consuming OAuth 2.0",permalink:"/hydra/docs/next/integration"}},s=[{value:"Mobile &amp; Browser (SPA) Authorization",id:"mobile--browser-spa-authorization",children:[{value:"Creating a public OAuth 2.0 Client",id:"creating-a-public-oauth-20-client",children:[]}]},{value:"Key rotation",id:"key-rotation",children:[{value:"Rotation of JSON Web Token Signing Keys",id:"rotation-of-json-web-token-signing-keys",children:[]},{value:"Rotation of HMAC Token Signing and Database and Cookie Encryption Keys",id:"rotation-of-hmac-token-signing-and-database-and-cookie-encryption-keys",children:[]}]},{value:"OAuth 2.0",id:"oauth-20",children:[{value:"Audience",id:"audience",children:[]},{value:"JSON Web Tokens",id:"json-web-tokens",children:[]},{value:"OAuth 2.0 Client Authentication with RSA private/public keypairs",id:"oauth-20-client-authentication-with-rsa-privatepublic-keypairs",children:[]}]},{value:"OpenID Connect",id:"openid-connect",children:[{value:"Subject Identifier Algorithms",id:"subject-identifier-algorithms",children:[]}]},{value:"CORS",id:"cors",children:[]},{value:"Cookies",id:"cookies",children:[]}],l={rightToc:s};function b(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(i.a)({},l,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"This guide aims to help setting up a production system with ORY Hydra."),Object(o.b)("h2",{id:"mobile--browser-spa-authorization"},"Mobile & Browser (SPA) Authorization"),Object(o.b)("p",null,"We have an\n",Object(o.b)("a",Object(i.a)({parentName:"p"},{href:"https://www.ory.sh/oauth2-for-mobile-app-spa-browser"}),"excellent blog post")," on\nthis topic. Read it now!"),Object(o.b)("h3",{id:"creating-a-public-oauth-20-client"},"Creating a public OAuth 2.0 Client"),Object(o.b)("p",null,"You can create a public OAuth 2.0 Client (e.g. for the authorize code + PKCE or\nimplicit flow) with the CLI"),Object(o.b)("pre",null,Object(o.b)("code",Object(i.a)({parentName:"pre"},{}),"hydra clients create --endpoint http://ory-hydra-admin-api --token-endpoint-auth-method none\n")),Object(o.b)("p",null,"or by setting in the HTTP API JSON body when POSTing to ",Object(o.b)("inlineCode",{parentName:"p"},"/clients"),":"),Object(o.b)("pre",null,Object(o.b)("code",Object(i.a)({parentName:"pre"},{}),'{\n    "client_id": "...",\n    "token_endpoint_auth_method": "none"\n}\n')),Object(o.b)("p",null,"Be aware that when making requests to ",Object(o.b)("inlineCode",{parentName:"p"},"/oauth2/token")," with a public OAuth 2.0\nClient, you can not authenticate with the HTTP Basic Authorization but must\ninclude the ",Object(o.b)("inlineCode",{parentName:"p"},"client_id")," in the POST body."),Object(o.b)("h2",{id:"key-rotation"},"Key rotation"),Object(o.b)("p",null,"There are two types of key rotation:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Rotation of JSON Web Token Signing Keys"),Object(o.b)("li",{parentName:"ul"},"Rotation of HMAC Token Signing and Database and Cookie Encryption Keys")),Object(o.b)("h3",{id:"rotation-of-json-web-token-signing-keys"},"Rotation of JSON Web Token Signing Keys"),Object(o.b)("p",null,"JSON Web Token Signing Key rotation is simple with ORY Hydra. You can rotate\nOpenID Connect ID Token and OAuth 2.0 Access Tokens, when using the JSON Web\nToken strategy, keys with one simple command."),Object(o.b)("p",null,"ORY Hydra takes the latest key from the key store to sign JSON Web Tokens. All\npublic keys will be shown at\n",Object(o.b)("inlineCode",{parentName:"p"},"http://ory-hydra-public-api/.well-known/jwks.json"),"."),Object(o.b)("h4",{id:"openid-connect-id-token"},"OpenID Connect ID Token"),Object(o.b)("pre",null,Object(o.b)("code",Object(i.a)({parentName:"pre"},{}),"hydra keys create --endpoint=http://ory-hydra-admin-api/ hydra.openid.id-token -a RS256\n")),Object(o.b)("h4",{id:"oauth-20-access-tokens-json-web-token"},"OAuth 2.0 Access Tokens (JSON Web Token)"),Object(o.b)("blockquote",null,Object(o.b)("p",{parentName:"blockquote"},"This will only work when using the JWT access token strategy. Otherwise, this\nwill have no effect.")),Object(o.b)("pre",null,Object(o.b)("code",Object(i.a)({parentName:"pre"},{}),"hydra keys create --endpoint=http://ory-hydra-admin-api/ hydra.jwt.access-token -a RS256\n")),Object(o.b)("h3",{id:"rotation-of-hmac-token-signing-and-database-and-cookie-encryption-keys"},"Rotation of HMAC Token Signing and Database and Cookie Encryption Keys"),Object(o.b)("p",null,"Rotating database encryption keys is done by prepending the new encryption key\nto the respective configuration value. Assuming configuration"),Object(o.b)("pre",null,Object(o.b)("code",Object(i.a)({parentName:"pre"},{className:"language-yaml"}),"secrets:\n  cookie:\n    - the-old-cookie-encryption-key\n  system:\n    - the-old-system-encryption-key\n")),Object(o.b)("p",null,"one would add the new keys as follows"),Object(o.b)("pre",null,Object(o.b)("code",Object(i.a)({parentName:"pre"},{className:"language-yaml"}),"secrets:\n  cookie:\n    - the-new-cookie-encryption-key # the new key must be the first entry\n    - the-old-cookie-encryption-key\n  system:\n    - the-new-system-encryption-key # the new key must be the first entry\n    - the-old-system-encryption-key\n")),Object(o.b)("blockquote",null,Object(o.b)("p",{parentName:"blockquote"},"It is very important that the new key is the first entry in the list as only\nthe first key is used for encryption while all keys from the list are used for\ndecryption. Please note that existing data will not be automatically\nre-encrypted using the new key. Only new data will be signed and encrypted\nusing the new key. It is therefore imperative that the old key is added to the\nlist, unless you want to also invalidate all data that was signed or encrypted\nusing the old key.")),Object(o.b)("h2",{id:"oauth-20"},"OAuth 2.0"),Object(o.b)("h3",{id:"audience"},"Audience"),Object(o.b)("p",null,"There are two types of audience concept in the context of OAuth 2.0 and OpenID\nConnect:"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},'OAuth 2.0: Access and Refresh Tokens are "internal-facing". The ',Object(o.b)("inlineCode",{parentName:"li"},"aud")," claim\nof an OAuth 2.0 Access and Refresh token defines at which ",Object(o.b)("em",{parentName:"li"},"endpoints")," the\ntoken can be used."),Object(o.b)("li",{parentName:"ol"},'OpenID Connect: The ID Token is "external-facing". The ',Object(o.b)("inlineCode",{parentName:"li"},"aud")," claim of an\nOpenID Connect ID Token defines which ",Object(o.b)("em",{parentName:"li"},"clients")," should accept it.")),Object(o.b)("p",null,"While modifying the audience of an ID Token is not desirable, specifying the\naudience of an OAuth 2.0 Access Token is. This is not defined as an IETF\nStandard but is considered good practice in certain environments."),Object(o.b)("p",null,"For this reason, Hydra allows you to control the aud claim of the access token.\nTo do so, you must specify the intended audiences in the OAuth 2.0 Client's\nmetadata on a per-client basis:"),Object(o.b)("pre",null,Object(o.b)("code",Object(i.a)({parentName:"pre"},{}),'{\n    "client_id": "...",\n    "audience": ["https://api.my-cloud.com/user", "https://some-tenant.my-cloud.com/"]\n}\n')),Object(o.b)("p",null,"The audience is a list of case-sensitive URLs. ",Object(o.b)("strong",{parentName:"p"},"URLs must not contain\nwhitespaces"),"."),Object(o.b)("h4",{id:"oauth-20-authorization-code-implicit-hybrid-flows"},"OAuth 2.0 Authorization Code, Implicit, Hybrid Flows"),Object(o.b)("p",null,"When performing an OAuth 2.0 authorize code, implicit, or hybrid flow, you can\nrequest audiences at the ",Object(o.b)("inlineCode",{parentName:"p"},"/oauth2/auth")," endpoint\n",Object(o.b)("inlineCode",{parentName:"p"},"https://my-hydra.com/oauth2/auth?client_id=...&scope=...&audience=https%3A%2F%2Fapi.my-cloud.com%2Fuser+https%3A%2F%2Fsome-tenant.my-cloud.com%2F"),"\nwhich requests audiences ",Object(o.b)("inlineCode",{parentName:"p"},"https://api.my-cloud.com/user")," and\n",Object(o.b)("inlineCode",{parentName:"p"},"https://some-tenant.my-cloud.com/"),"."),Object(o.b)("p",null,"The ",Object(o.b)("inlineCode",{parentName:"p"},"audience")," query parameter may contain multiple strings separated by a\nurl-encoded space (",Object(o.b)("inlineCode",{parentName:"p"},"+")," or ",Object(o.b)("inlineCode",{parentName:"p"},"%20"),"). The audience values themselves must also be\nurl encoded. The values will be validated against the whitelisted audiences\ndefined in the OAuth 2.0 Client:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"An OAuth 2.0 Client with the allowed audience ",Object(o.b)("inlineCode",{parentName:"li"},"https://api.my-cloud/user")," is\nallowed to request audience values ",Object(o.b)("inlineCode",{parentName:"li"},"https://api.my-cloud/user"),Object(o.b)("inlineCode",{parentName:"li"},"https://api.my-cloud/user/1234")," but not ",Object(o.b)("inlineCode",{parentName:"li"},"https://api.my-cloud/not-user")," nor\n",Object(o.b)("inlineCode",{parentName:"li"},"https://something-else/"),".")),Object(o.b)("p",null,"The requested audience from the query parameter is then part of the login and\nconsent request payload as field ",Object(o.b)("inlineCode",{parentName:"p"},"requested_access_token_audience"),". You can then\nalter the audience using ",Object(o.b)("inlineCode",{parentName:"p"},"grant_audience.access_token")," when accepting the\nconsent request:"),Object(o.b)("pre",null,Object(o.b)("code",Object(i.a)({parentName:"pre"},{}),'hydra.acceptConsentRequest(challenge, {\n  // ORY Hydra checks if requested audiences are allowed by the client, so we can simply echo this.\n  grant_audience: {\n    access_token: response.requested_access_token_audience,\n    // or, for example:\n    // access_token: ["https://api.my-cloud/not-user"]\n  },\n\n  // ... remember: false\n  // ...\n})\n')),Object(o.b)("p",null,"When introspecting the OAuth 2.0 Access Token, the response payload will include\nthe audience:"),Object(o.b)("pre",null,Object(o.b)("code",Object(i.a)({parentName:"pre"},{}),'{\n  "active": true,\n  // ...\n  "audience": ["https://api.my-cloud/user", "https://api.my-cloud/user/1234"]\n}\n')),Object(o.b)("h4",{id:"oauth-20-client-credentials-grant"},"OAuth 2.0 Client Credentials Grant"),Object(o.b)("p",null,"When performing the client credentials grant, the audience parameter from the\nPOST body of the ",Object(o.b)("inlineCode",{parentName:"p"},"/oauth2/token")," is decoded and validated according to the same\nrules of the previous section, except for the login and consent part which does\nnot exist for this flow."),Object(o.b)("h3",{id:"json-web-tokens"},"JSON Web Tokens"),Object(o.b)("p",null,"ORY Hydra issues opaque OAuth 2.0 Access Tokens per default for the following\nreasons:"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},Object(o.b)("strong",{parentName:"li"},"OAuth 2.0 Access Tokens represent internal state but are public\nknowledge:")," An Access Token often contains internal data (e.g. session data)\nor other sensitive data (e.g. user roles and permissions) and is sometimes\nused as a means of transporting system-relevant information in a stateless\nmanner. Therefore, making these tokens transparent (by using JSON Web Tokens\nas Access Tokens) comes with risk of exposing this information accidentally,\nand with the downside of not storing this information in the OAuth 2.0 Access\nToken at all."),Object(o.b)("li",{parentName:"ol"},Object(o.b)("strong",{parentName:"li"},"JSON Web Tokens can not hold secrets:")," Unless encrypted, JSON Web Tokens\ncan be read by everyone, including 3rd Parties. Therefore, they can not keep\nsecrets. This point is similar to (1), but it is important to stress this."),Object(o.b)("li",{parentName:"ol"},Object(o.b)("strong",{parentName:"li"},"Access Tokens as JSON Web Tokens can not be revoked:"),' Well, you can revoke\nthem, but they will be considered valid until the "expiry" of the token is\nreached. Unless, of course, you have a blacklist or check with Hydra if the\ntoken was revoked, which however defeats the purpose of using JSON Web Tokens\nin the first place.'),Object(o.b)("li",{parentName:"ol"},Object(o.b)("strong",{parentName:"li"},"Certain OpenID Connect features will not work")," when using JSON Web Tokens\nas Access Tokens, such as the pariwise subject identifier algorithm."),Object(o.b)("li",{parentName:"ol"},Object(o.b)("strong",{parentName:"li"},"There is a better solution: Use\n",Object(o.b)("a",Object(i.a)({parentName:"strong"},{href:"https://github.com/ory/oathkeeper"}),"ORY Oathkeeper"),"!"),' ORY Oathkeeper is a\nproxy you deploy in front of your services. It will "convert" ORY Hydra\'s\nopaque Access Tokens into JSON Web Tokens for your backend services. This\nallows your services to work without additional REST Calls while solving all\nprevious points. ',Object(o.b)("strong",{parentName:"li"},"We really recommend this option if you want JWTs!"))),Object(o.b)("p",null,"If you are not convinced that ORY Oathkeeper is the right tool for the job, you\ncan still enable JSON Web Tokens in ORY Hydra by setting:"),Object(o.b)("pre",null,Object(o.b)("code",Object(i.a)({parentName:"pre"},{className:"language-yaml"}),"strategies:\n  access_token: jwt\n")),Object(o.b)("p",null,"Be aware that only access tokens are formatted as JSON Web Tokens. Refresh\ntokens are not impacted by this strategy. By performing OAuth 2.0 Token\nIntrospection you can check if the token is still valid. If a token is revoked\nor otherwise blacklisted, the OAuth 2.0 Token Introspection will return\n",Object(o.b)("inlineCode",{parentName:"p"},'{ "active": false }'),". This is useful when you do not want to rely only on the\ntoken's expiry."),Object(o.b)("h4",{id:"json-web-token-validation"},"JSON Web Token Validation"),Object(o.b)("p",null,"You can validate JSON Web Tokens issued by ORY Hydra by pointing your ",Object(o.b)("inlineCode",{parentName:"p"},"jwt"),"\nlibrary (e.g. ",Object(o.b)("a",Object(i.a)({parentName:"p"},{href:"https://github.com/auth0/node-jwks-rsa"}),"node-jwks-rsa"),") to\n",Object(o.b)("inlineCode",{parentName:"p"},"http://ory-hydra-public-api/.well-known/jwks.json"),". All necessary keys are\navailable there."),Object(o.b)("h3",{id:"oauth-20-client-authentication-with-rsa-privatepublic-keypairs"},"OAuth 2.0 Client Authentication with RSA private/public keypairs"),Object(o.b)("p",null,"ORY Hydra supports OAuth 2.0 Client Authentication with RSA private/public\nkeypairs. This authentication method replaces the classic HTTP Basic\nAuthorization and HTTP POST Authorization schemes. Instead of sending the\n",Object(o.b)("inlineCode",{parentName:"p"},"client_id")," and ",Object(o.b)("inlineCode",{parentName:"p"},"client_secret"),", you authenticate the client with a signed JSON\nWeb Token."),Object(o.b)("p",null,"To enable this feature for a specific OAuth 2.0 Client, you must set\n",Object(o.b)("inlineCode",{parentName:"p"},"token_endpoint_auth_method")," to ",Object(o.b)("inlineCode",{parentName:"p"},"private_key_jwt")," and register the public key of\nthe RSA signing key either using the ",Object(o.b)("inlineCode",{parentName:"p"},"jwks_uri")," or ",Object(o.b)("inlineCode",{parentName:"p"},"jwks")," fields of the client."),Object(o.b)("p",null,"When authenticating the client at the token endpoint, you generate and sign\n(with the RSA private key) a JSON Web Token with the following claims:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"iss"),": REQUIRED. Issuer. This MUST contain the client_id of the OAuth Client."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"sub"),": REQUIRED. Subject. This MUST contain the client_id of the OAuth Client."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"aud"),": REQUIRED. Audience. The aud (audience) Claim. Value that identifies the\nAuthorization Server (ORY Hydra) as an intended audience. The Authorization\nServer MUST verify that it is an intended audience for the token. The Audience\nSHOULD be the URL of the Authorization Server's Token Endpoint."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"jti"),": REQUIRED. JWT ID. A unique identifier for the token, which can be used\nto prevent reuse of the token. These tokens MUST only be used once, unless\nconditions for reuse were negotiated between the parties; any such negotiation\nis beyond the scope of this specification."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"exp"),": REQUIRED. Expiration time on or after which the ID Token MUST NOT be\naccepted for processing."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"iat"),": OPTIONAL. Time at which the JWT was issued.")),Object(o.b)("p",null,"When making a request to the ",Object(o.b)("inlineCode",{parentName:"p"},"/oauth2/token")," endpoint, you include\n",Object(o.b)("inlineCode",{parentName:"p"},"client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer"),"\nand ",Object(o.b)("inlineCode",{parentName:"p"},"client_assertion=<signed-jwt>")," in the request body:"),Object(o.b)("pre",null,Object(o.b)("code",Object(i.a)({parentName:"pre"},{}),"POST /oauth2/token HTTP/1.1\nHost: my-hydra.com\nContent-Type: application/x-www-form-urlencoded\n\ngrant_type=authorization_code&\ncode=i1WsRn1uB1&\nclient_id=s6BhdRkqt3&\nclient_assertion_type=\nurn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&\nclient_assertion=PHNhbWxwOl ... ZT\n")),Object(o.b)("p",null,"Here's what a client with a ",Object(o.b)("inlineCode",{parentName:"p"},"jwks")," looks like:"),Object(o.b)("pre",null,Object(o.b)("code",Object(i.a)({parentName:"pre"},{className:"language-json"}),'{\n  "client_id": "client-jwks",\n  "jwks": {\n    "keys": [\n      {\n        "kty": "RSA",\n        "n": "jL7h5wc-yeMUsHGJHc0xe9SbTdaLKXMHvcIHQck20Ji7SvrHPdTDQTvZtTDS_wJYbeShcCrliHvbJRSZhtEe0mPJpyWg3O_HkKy6_SyHepLK-_BR7HfcXYB6pVJCG3BW-lVMY7gl5sULFA74kNZH50h8hdmyWC9JgOHn0n3YLdaxSWlhctuwNPSwqwzY4qtN7_CZub81SXWpKiwj4UpyB10b8rM8qn35FS1hfsaFCVi0gQpd4vFDgFyqqpmiwq8oMr8RZ2mf0NMKCP3RXnMhy9Yq8O7lgG2t6g1g9noWbzZDUZNc54tv4WGFJ_rJZRz0jE_GR6v5sdqsDTdjFquPlQ",\n        "e": "AQAB"\n      }\n    ]\n  },\n  "token_endpoint_auth_method": "private_key_jwt"\n}\n')),Object(o.b)("p",null,"And with ",Object(o.b)("inlineCode",{parentName:"p"},"jwks_uri"),":"),Object(o.b)("pre",null,Object(o.b)("code",Object(i.a)({parentName:"pre"},{className:"language-json"}),'{\n  "client_id": "client-jwks-uri",\n  "jwks_uri": "http://path-to-my-public/keys.json",\n  "token_endpoint_auth_method": "private_key_jwt"\n}\n')),Object(o.b)("p",null,"The ",Object(o.b)("inlineCode",{parentName:"p"},"jwks_uri")," must return a JSON object containing the public keys associated\nwith the OAuth 2.0 Client:"),Object(o.b)("pre",null,Object(o.b)("code",Object(i.a)({parentName:"pre"},{className:"language-json"}),'{\n  "keys": [\n    {\n      "kty": "RSA",\n      "n": "jL7h5wc-yeMUsHGJHc0xe9SbTdaLKXMHvcIHQck20Ji7SvrHPdTDQTvZtTDS_wJYbeShcCrliHvbJRSZhtEe0mPJpyWg3O_HkKy6_SyHepLK-_BR7HfcXYB6pVJCG3BW-lVMY7gl5sULFA74kNZH50h8hdmyWC9JgOHn0n3YLdaxSWlhctuwNPSwqwzY4qtN7_CZub81SXWpKiwj4UpyB10b8rM8qn35FS1hfsaFCVi0gQpd4vFDgFyqqpmiwq8oMr8RZ2mf0NMKCP3RXnMhy9Yq8O7lgG2t6g1g9noWbzZDUZNc54tv4WGFJ_rJZRz0jE_GR6v5sdqsDTdjFquPlQ",\n      "e": "AQAB"\n    }\n  ]\n}\n')),Object(o.b)("h2",{id:"openid-connect"},"OpenID Connect"),Object(o.b)("h3",{id:"subject-identifier-algorithms"},"Subject Identifier Algorithms"),Object(o.b)("p",null,"Hydra supports two\n",Object(o.b)("a",Object(i.a)({parentName:"p"},{href:"http://openid.net/specs/openid-connect-core-1_0.html#SubjectIDTypes"}),"Subject Identifier Algorithms"),":"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"public"),": This provides the same ",Object(o.b)("inlineCode",{parentName:"li"},"sub")," (subject) value to all Clients\n(default)."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"pairwise"),": This provides a different ",Object(o.b)("inlineCode",{parentName:"li"},"sub")," value to each Client, so as not to\nenable Clients to correlate the End-User's activities without permission.")),Object(o.b)("p",null,"You can enable either one or both algorithms using the following configuration\nlayout:"),Object(o.b)("pre",null,Object(o.b)("code",Object(i.a)({parentName:"pre"},{className:"language-yaml"}),"oidc:\n  subject_identifiers:\n    enabled:\n      - public\n      - pairwise\n")),Object(o.b)("p",null,"When ",Object(o.b)("inlineCode",{parentName:"p"},"pairwise")," is enabled, you must also set\n",Object(o.b)("inlineCode",{parentName:"p"},"oidc.subject_identifiers.pairwise.salt"),". The salt is used to obfuscate the\n",Object(o.b)("inlineCode",{parentName:"p"},"sub")," value:"),Object(o.b)("pre",null,Object(o.b)("code",Object(i.a)({parentName:"pre"},{className:"language-yaml"}),"oidc:\n  subject_identifiers:\n    enabled:\n      - public\n      - pairwise\n    pairwise:\n      salt: some-salt\n")),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"},"This value should not be changed once set in production. Changing it will\ncause all client applications to receive new user IDs from ORY Hydra which will\nlead to serious complications with authentication on their side!")),Object(o.b)("p",null,"Each OAuth 2.0 Client has a configuration field ",Object(o.b)("inlineCode",{parentName:"p"},"subject_type"),". The value of\nthat ",Object(o.b)("inlineCode",{parentName:"p"},"subject_type")," is either ",Object(o.b)("inlineCode",{parentName:"p"},"public")," or ",Object(o.b)("inlineCode",{parentName:"p"},"pairwise"),". If the identifier\nalgorithm is enabled, ORY Hydra will choose the right strategy automatically."),Object(o.b)("p",null,"While ORY Hydra handles ",Object(o.b)("inlineCode",{parentName:"p"},"sub")," obfuscation out of the box, you may also override\nthis value with your own obfuscated ",Object(o.b)("inlineCode",{parentName:"p"},"sub")," value by setting\n",Object(o.b)("inlineCode",{parentName:"p"},"force_subject_identifier")," when accepting the login challenge in your user login\napp."),Object(o.b)("h2",{id:"cors"},"CORS"),Object(o.b)("p",null,"Both ORY Hydra's Admin and Public endpoints support CORS. For detailed\ninformation, head over to the exemplary\n",Object(o.b)("a",Object(i.a)({parentName:"p"},{href:"https://github.com/ory/hydra/blob/master/docs/config.yaml"}),"config file"),"."),Object(o.b)("p",null,"For CORS to work properly, we encourage to set the following values:"),Object(o.b)("pre",null,Object(o.b)("code",Object(i.a)({parentName:"pre"},{className:"language-yaml"}),"serve:\n  admin:\n    cors:\n      enabled: true\n      allowed_origins:\n        - https://example.com\n        - https://*.example.com\n      allowed_methods:\n        - POST\n        - GET\n        - PUT\n        - PATCH\n        - DELETE\n      allowed_headers:\n        - Authorization\n      exposed_headers:\n        - Content-Type\n  public:\n    cors:\n      enabled: true\n      allowed_origins:\n        - https://example.com\n        - https://*.example.com\n      allowed_methods:\n        - POST\n        - GET\n        - PUT\n        - PATCH\n        - DELETE\n      allowed_headers:\n        - Authorization\n      exposed_headers:\n        - Content-Type\n")),Object(o.b)("p",null,"Keep in mind that the OAuth 2.0 Authorization Endpoint (",Object(o.b)("inlineCode",{parentName:"p"},"/oauth2/auth"),") does not\nexpose CORS by design. This endpoint should never be consumed in a CORS-fashion.\nSome endpoints (",Object(o.b)("inlineCode",{parentName:"p"},"/oauth2/token"),", ",Object(o.b)("inlineCode",{parentName:"p"},"/userinfo"),", ",Object(o.b)("inlineCode",{parentName:"p"},"/oauth2/revoke"),") additionally\ninclude URLs listed in field ",Object(o.b)("inlineCode",{parentName:"p"},"allowed_cors_origins")," of the OAuth 2.0 Client that\nis making the request. For example, OAuth 2.0 Client"),Object(o.b)("pre",null,Object(o.b)("code",Object(i.a)({parentName:"pre"},{className:"language-json"}),'{\n  "client_id": "foo",\n  "allowed_cors_origins": ["https://foo-bar.com/"]\n}\n')),Object(o.b)("p",null,"is allowed to make CORS request to ",Object(o.b)("inlineCode",{parentName:"p"},"/oauth2/token")," from origin\n",Object(o.b)("inlineCode",{parentName:"p"},"https://foo-bar.com/")," even if that origin is not listed in\n",Object(o.b)("inlineCode",{parentName:"p"},"public.cors.allowed_origins"),"."),Object(o.b)("h2",{id:"cookies"},"Cookies"),Object(o.b)("p",null,"By default, cookies sent by the Hydra Public endpoints are set without\nexplicitly specifying a SameSite mode. If you wish for these cookies to be set\nwith a mode you can use the ",Object(o.b)("inlineCode",{parentName:"p"},"serve.cookies.same_site_mode")," setting. Possible\nvalues are ",Object(o.b)("inlineCode",{parentName:"p"},"Strict"),", ",Object(o.b)("inlineCode",{parentName:"p"},"Lax")," or ",Object(o.b)("inlineCode",{parentName:"p"},"None"),"."),Object(o.b)("p",null,"If you wish to embed requests to hydra on a third party site (for example an\niframe that periodically polls to check session status) you will need to set the\nmode to ",Object(o.b)("inlineCode",{parentName:"p"},"None"),"."))}b.isMDXComponent=!0},199:function(e,t,n){"use strict";n.d(t,"a",(function(){return p})),n.d(t,"b",(function(){return h}));var i=n(0),a=n.n(i);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 c(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 s(e,t){if(null==e)return{};var n,i,a=function(e,t){if(null==e)return{};var n,i,a={},o=Object.keys(e);for(i=0;i<o.length;i++)n=o[i],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(i=0;i<o.length;i++)n=o[i],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=a.a.createContext({}),b=function(e){var t=a.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=b(e.components);return a.a.createElement(l.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},u=Object(i.forwardRef)((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,r=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=b(n),u=i,h=p["".concat(r,".").concat(u)]||p[u]||d[u]||o;return n?a.a.createElement(h,c({ref:t},l,{components:n})):a.a.createElement(h,c({ref:t},l))}));function h(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=u;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:i,r[1]=c;for(var l=2;l<o;l++)r[l]=n[l];return a.a.createElement.apply(null,r)}return a.a.createElement.apply(null,n)}u.displayName="MDXCreateElement"}}]);