GithubHelp home page GithubHelp logo

Comments (11)

pedramp20 avatar pedramp20 commented on June 16, 2024 4

As discussed, the cdn (CloudFront) and api need to be on the same domain. To achieve that I added the functionality that I suggested to the video plugin, where it allows users to set a custom domain for the CloudFront (#329) @wizage @nathanagez
Then you can utilise APIMapping to map the same domain to your api but the bigger issue is that the frontend server (origin) also needs to be on the same domain and for all of those to be on the same domain, it requires major changes and integration between video plugin and the main cli, otherwise CORS is inevitable. (Please note that CORS is required for subdomains)

To be able to issue a valid cookie on the server side, you need to have a domain that you own with a valid SSL anyway. So to get it working with the current situation, you can create a rest api using cli. Then add these custom resources to set a custom domain to the api.

              "Parameters": {
		"env": {
			"Type": "String"
		},
		"certificateArn": {
			"Type": "String",
			"Default": "CertificateArn"
		},
		"hostedZoneId": {
			"Type": "String",
			"Default": "HostedZoneId"
		},
		"customDomain": {
			"Type": "String",
			"Default": "Custom Domain"
		}
	      },
....

		"ApiGWCustomDomain": {
			"Type": "AWS::ApiGateway::DomainName",
			"Properties": {
				"DomainName": {
					"Fn::Join": [
						"",
						[
							{
								"Ref": "env"
							},
							"-",
							{
								"Ref": "customDomain"
							}
						]
					]
				},
				"CertificateArn": {
					"Ref": "certificateArn"
				},
				"EndpointConfiguration": {
					"Types": [ "EDGE" ]
				},
				"SecurityPolicy": "TLS_1_2"
			}
		},
		"Route53RecordSetGroup": {
			"Type": "AWS::Route53::RecordSet",
			"Properties": {
				"Name": {
					"Fn::Join": [
						"",
						[
							{
								"Ref": "env"
							},
							"-",
							{
								"Ref": "customDomain"
							}
						]
					]
				},
				"Type": "A",
				"HostedZoneId": {
					"Ref": "hostedZoneId"
				},
				"AliasTarget": {
					"DNSName": {
						"Fn::GetAtt": [ "ApiGWCustomDomain", "DistributionDomainName" ]
					},
					"EvaluateTargetHealth": false,
					"HostedZoneId": {
						"Fn::GetAtt": [ "ApiGWCustomDomain", "DistributionHostedZoneId" ]
					}
				}
			}
		},

Then add this mapping to your api CloudFormation template

                    "APIMapping": {
			"Type": "AWS::ApiGateway::BasePathMapping",
			"Properties": {
				"BasePath": "<your path>",
				"DomainName": {
					"Fn::Join": [
						"",
						[
							{
								"Ref": "env"
							},
							"-",
							{
								"Ref": "customDomain"
							}
						]
					]
				},
				"RestApiId": {
					"Ref": "<your api id>"
				},
				"Stage": {
					"Fn::If": [
						"ShouldNotCreateEnvResources",
						"Prod",
						{
							"Ref": "env"
						}
					]
				}
			}
		}

and finally change the RootUrl output of the api cloudformation template. So when you call the api using amplify front-end library, it uses the custom domain not the default api gateway url.

	"Outputs": {
		"RootUrl": {
			"Description": "Root URL of the API gateway",
			"Value": {
				"Fn::Join": [
					"",
					[
						"https://",
            {
              "Ref": "env"
            },
            "-",
            {
              "Ref": "customDomain"
            },
            "/<your path>"
					]
				]
			}
		},

in the lambda function connected to the api, use almost the same code as the default CFTokenGenerator just change sigend url to signed cookies by using the following method

 const signedCookie = signer.getSignedCookie(params);

Please note that to set a cookie with CORS you need to set the withCredentials flag when making the request and the server needs to return the Access-Control-Allow-Credentials: true header. You also need to change the Access-Control-Allow-Origin header to a specific origin and can't use wildcards on a request that uses credentials.

// Enable CORS for all methods
app.use(function (request, res, next) {
  const allowedOrigins = ['https://<your domain>', 'xxxx'];
  const origin = request.headers.origin;
  if (allowedOrigins.includes(origin)) {
    res.setHeader('Access-Control-Allow-Origin', origin);
  }
  res.header('Access-Control-Allow-Headers', '*');
  res.header('Access-Control-Allow-Credentials', 'true');
  res.header('Access-Control-Allow-Methods', 'GET,HEAD,OPTIONS,POST,PUT');
  //intercept the OPTIONS call so we don't double up on calls to the integration
  if ('OPTIONS' === request.method) {
    res.send(200);
  } else {
    next();
  }
});

Last but not least set the cookies in the response header

app.post('/<your path>', async (req, res) => {
  // handle authorisation if the caller can get the cookies

  const cookies = await signPath(req.body);
  Object.keys(cookies).map((cookieName) => {
    res.cookie(cookieName, cookies[cookieName], { httpOnly: true, path: "/", domain: ".<your domain>", sameSite: "None", secure: true });
  })
...
  res.json({ body })
});

Please make sure that you set withCredentials flag when calling the api to store the cookies. Then call cloudfront with the same withCredentials flag and cookies should be attached and hence you should get 200.

from amplify-video.

wizage avatar wizage commented on June 16, 2024 2

So using signed cookies is not currently supported. That being said it isn't that much a lift. The function that is used to create the urls is very similiar to the one you need for cookies.

As far as cookies/urls, the concept is the same. You can easily just add the /* to the end of a request to get a cookie and you now use it for any file that falls under that /. Since we sort videos by id it would be something like / and boom you now have all the hls files authed for that cookie/url.

Now the complicated thing where this gets to the hard part is talking about how cookies work vs urls. Urls are easy they work most everywhere and great for POCing. Cookies are better for production and big sites but take a trade off of you need a domain to work with. Cookies work by using a special header called Set-Cookie that is returned in the response. Set-Cookie needs to be called from the same domain as the request coming from url. I.E. example.com/getCookie and example.com/movie.id/master.hls.

This is why cookies will most likely see a long time before implementation via Amplify Video as it requires working w/ Route53 and other DNS products making the solution not as easy to be a one size fits all.

from amplify-video.

pedramp20 avatar pedramp20 commented on June 16, 2024 1

@wizage you're welcome. Happy to contribute. I believe we can even add the rest api creation to the video plugin, so the full solution is available to everyone via the cli. To do so we need to discuss it further, as I don't want to reimplement the functionalities that are already available in the main cli again and duplicate them here.

P.s. In this branch I have added the api gateway creation to video plugin. The only remaining part is updating amplify meta after resource create/remove. I looked at the CLI code and found the amplify helper but didn't want to duplicate them here. Lets have a quick chat. I'd appreciate your input.

from amplify-video.

kylekirkby avatar kylekirkby commented on June 16, 2024 1

@wizage @pedramp20 any idea when we can get this added to the core plugin?

from amplify-video.

pedramp20 avatar pedramp20 commented on June 16, 2024 1

@kylekirkby I created the pull request a while back but it seem like the team is busy with AWS reinvent. You can always pull the code and build it locally. Let me know if you need any help. The process of building the plugin locally is in the contribution guide.

from amplify-video.

nathanagez avatar nathanagez commented on June 16, 2024

Hi @pedramp20, Thank you for reporting this issue. It looks like it's related to video.js itself #131.

@wizage, is it a big effort to use signed cookies instead of signed urls? From what I understand, signed urls are useful for restricting access to a single file and signed cookies for restricting access to multiple files.

You want to provide access to multiple restricted files, for example, all of the files for a video in HLS format or all of the files in the subscribers' area of website.

https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-choosing-signed-urls-cookies.html

from amplify-video.

djsjr avatar djsjr commented on June 16, 2024

I am developing with Flutter, and I am currently successfully playing protected videos using the flutter video players "headers" parameter instead of signed URLs as explained in my comment here. This seems to work for now. Hopefully it does not cause me issues in the future based on what @wizage is saying.

from amplify-video.

wizage avatar wizage commented on June 16, 2024

This does work but is considered a work around for the way cookies work.

Cookies are typically supposed to be set using the Set-Cookie and stick around during the entire duration of the session (or when set to expire). This is just modifying the sent headers with the Cookie.

from amplify-video.

wizage avatar wizage commented on June 16, 2024

This is awesome! I will read through this in more depth after a new feature release coming this month. If I see this all correct this would be a huge addition to our plugin! Thanks a ton and can't wait to review this :)

from amplify-video.

kylekirkby avatar kylekirkby commented on June 16, 2024

@pedramp20 the process was a bit more involved for us. I'll have to write up some details at some point but we've got signed cookies working now.

from amplify-video.

pedramp20 avatar pedramp20 commented on June 16, 2024

@kylekirkby appreciate if you could point out the differences and how you got the withCredentials working using amplify http client?

from amplify-video.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.