You certainly can't trust the Origin header generally. You can trust the origin header when it is a request from a browser, but if malicious attackers are using your endpoint directly via a client they control, then the origin header is meaningless. So whether or not it helps depends on the circumstances.
The simplest way is the same way everyone secures API access - grant API tokens to users and have your clients register their API token with your javascript on page load. You might often see things like this:
<script type="text/javascript" src="//awesome.service.com/js">
<script type="text/javascript">
AwesomeService::SetPublicToken('THISISMYAUTHTOKENASSIGNEDBYYOURSYSTEM');
</script>
Now obviously that authentication token is public - anyone viewing your client's page can see their token and steal it. Hence the emphasis on Public token. Different services address this issue in different ways, depending on what you are trying to secure. The most common solution is to have different private and public keys with different security rules or options associated with them. Let's consider two examples: a mapping service (i.e. google maps) and a credit card processor.
Mapping Service
Let's imagine a javascript file that draws maps in a browser. You want your clients authenticated so that you can make sure everyone is paying for this service. This can be effectively protected by simple public authentication keys and allowing the client to configure their list of allowed hosts. Since this is really only useful if the API calls are used to display info in a browser, it is a fair assumption that your API will be called from a browser, and therefore using an Origin header check against your list of white-listed domain names (provided by the client) makes sure it is being used as intended. This makes sure that the public key isn't just copied to a new website and used to get free service by someone else.
Regarding usage outside of a browser, there is really no motivation for someone to do that other than spite. Sure, someone could copy your public token and generate a script that makes API calls using it and pretending to be from a white-listed domain (because using a non-browser HTTP client lets you easily spoof the Origin header), but why? Since this mapping service just returns maps to display in the browser, there is no gain. The only reason to really do it is if you really don't like the business you stole the public auth key from, and want to run up a large bill on their service. Probably not the most common attack vector.
So in a case like this public authentication tokens and an origin check are more than sufficient for the use case.
Credit card processor
Imagine you have a service where you have truly sensitive information - credit cards! You want your clients to be able to process credit card transactions using your handy javascript file so that it can be done in a PCI compliant way (i.e. Stripe) without leaving the checkout page. You need this to happen in a browser, but Public Tokens plus Origin checks are no longer enough. With direct API access (via Origin spoofing), a malicious user may use the API to refund their own credit card, potentially stealing money from the client's business.
So what do you do? Separate out secure actions with a private authorization token, and only allow the public authentication token to request actions. Those actions must then be authorized via a separate API call from the client's server itself using a private key not shared with anyone. For Stripe it looks like this:
- Javascript library in end-user's browser collects credit card information
- Javascript library in end-user's browser sends CC info to Stripe using public key
- Stripe sends back a single-use "transaction" token that is useless on its own
- Javascript in end-user's browser sends authorization token to (e.g.) e-commerce site that is using stripe service
- E-commerce site sends additional API call directly to stripe with single use "transaction" token using a private authorization token, telling Stripe what to actually do with the corresponding credit card (aka bill it, refund it, etc...).
This is obviously a more complicated flow, but it is necessary to protect sensitive API calls because nothing in the browser is private and there is no way to guarantee that you are actually talking to a browser if you are looking from the perspective of an API service.
I suppose I'm answering by example, but it's hard to give a comprehensive answer because so much depends on the circumstances. The details of your service decide what steps you actually take, but the short of it is that truly sensitive services can't really be protected if only client-side javascript is involved. Again, the reason is because everything on the client-side is effectively public information, and all aspects of an HTTP request can be spoofed.