# Magic API Proxy
This is a *stateless* API proxy that allows creation and use of *access-limited* API tokens.
Basically, it's identity and access management for API tokens.
## Why is this useful?
GitHub's API tokens (or other APIs, like DigitalOcean's) do not allow fine-grained control over which actions a token can perform (see this [Dear GitHub issue](https://github.com/dear-github/dear-github/issues/113)). For example, you basically have to create a token that has full control over a repository to allow a token to just apply labels to issues.
This can be problematic. When you have many jobs, processes, and/or bots interacting with the GitHub API you increase the likelihood that a token could be compromised and tokens with broad permissions have very high consequences.
This proxy allows you to create API tokens with fine-grained permissions (a *magic token*) and then talk to an API using those magic tokens through a proxy. The proxy validates the magic token is allows to perform the requested action and then forwards the request to the API using the real API token.
## What does *stateless* mean?
This proxy requires no backing storage and stores all of its state in the magic token itself. Although the plugin system permits to add a stateful layer if you so wish. e.g. allowing a token to create a record on a DNS provider, and delete it afterwards, but not delete any other record. *TODO*: document plugin system
## What? How?
The proxy uses asymmetric cryptography (a public and private key pair) and [JWTs](https://jwt.io) to encode its state into the magic token.
Each magic token is a simple JWT signed by the proxy's *private key* with these claims:
```
{
"iat": 1541616032,
"exp": 1699296032,
"token": "[long encrypted key]",
"allowed": [
"GET /user",
"GET /repos/theacodes/nox/issues"
]
}
```
The `token` claim is an encrypted version of the raw API token. It's encrypted using the proxy's **public key**, so that only the proxy itself can decrypt it (using its **private** key).
The allowed claim determines what the magic token has access to. This proxy has a basic, rudimentary scope implementation described below
The JWT is generated and signed by the proxy itself using its **private key**. This means the contents can not be tampered with without invalidating the JWT.
## Scoping
By default, this proxy has a simple scope strategy using the format:
```
METHOD /url/pattern
```
Where `METHOD` can be `GET`, `POST`, `PUT`, etc. and `/url/pattern` can be any regular expression that's used to check the URL.
For instance, to create a token that has access to any repository's issues in `someorg`, you could do:
```
GET /repos/someorg/.+?/issues
```
## Usage
TODO
## Disclaimer
This is was adaptaed from an unofficial inside-Google project, experimental. This is not a magic bullet for security. You assume all risks when using this project.
Raw data
{
"_id": null,
"home_page": "https://github.com/rienafairefr/magic-api-proxy",
"name": "magic-api-proxy",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.6",
"maintainer_email": "",
"keywords": "api github proxy",
"author": "adapted from Alethea Katherine Flowers",
"author_email": "matthieu@mmea.fr",
"download_url": "https://files.pythonhosted.org/packages/de/99/a9ceca12836b8ca24667a2132c85beca704191dcfaf4de5103c35f94188f/magic-api-proxy-0.1.14.tar.gz",
"platform": null,
"description": "# Magic API Proxy\n\nThis is a *stateless* API proxy that allows creation and use of *access-limited* API tokens.\n\nBasically, it's identity and access management for API tokens.\n\n\n## Why is this useful?\n\nGitHub's API tokens (or other APIs, like DigitalOcean's) do not allow fine-grained control over which actions a token can perform (see this [Dear GitHub issue](https://github.com/dear-github/dear-github/issues/113)). For example, you basically have to create a token that has full control over a repository to allow a token to just apply labels to issues.\n\nThis can be problematic. When you have many jobs, processes, and/or bots interacting with the GitHub API you increase the likelihood that a token could be compromised and tokens with broad permissions have very high consequences. \n\nThis proxy allows you to create API tokens with fine-grained permissions (a *magic token*) and then talk to an API using those magic tokens through a proxy. The proxy validates the magic token is allows to perform the requested action and then forwards the request to the API using the real API token.\n\n\n## What does *stateless* mean?\n\nThis proxy requires no backing storage and stores all of its state in the magic token itself. Although the plugin system permits to add a stateful layer if you so wish. e.g. allowing a token to create a record on a DNS provider, and delete it afterwards, but not delete any other record. *TODO*: document plugin system\n\n\n## What? How?\n\nThe proxy uses asymmetric cryptography (a public and private key pair) and [JWTs](https://jwt.io) to encode its state into the magic token.\n\nEach magic token is a simple JWT signed by the proxy's *private key* with these claims:\n\n```\n{\n \"iat\": 1541616032,\n \"exp\": 1699296032,\n \"token\": \"[long encrypted key]\",\n \"allowed\": [\n \"GET /user\",\n \"GET /repos/theacodes/nox/issues\"\n ]\n}\n```\n\nThe `token` claim is an encrypted version of the raw API token. It's encrypted using the proxy's **public key**, so that only the proxy itself can decrypt it (using its **private** key).\n\nThe allowed claim determines what the magic token has access to. This proxy has a basic, rudimentary scope implementation described below\n\nThe JWT is generated and signed by the proxy itself using its **private key**. This means the contents can not be tampered with without invalidating the JWT.\n\n\n## Scoping\n\nBy default, this proxy has a simple scope strategy using the format:\n\n```\nMETHOD /url/pattern\n```\n\nWhere `METHOD` can be `GET`, `POST`, `PUT`, etc. and `/url/pattern` can be any regular expression that's used to check the URL.\n\nFor instance, to create a token that has access to any repository's issues in `someorg`, you could do:\n\n```\nGET /repos/someorg/.+?/issues\n```\n\n\n## Usage\n\nTODO\n\n\n## Disclaimer\n\nThis is was adaptaed from an unofficial inside-Google project, experimental. This is not a magic bullet for security. You assume all risks when using this project.\n",
"bugtrack_url": null,
"license": "",
"summary": "A stateless API proxy",
"version": "0.1.14",
"split_keywords": [
"api",
"github",
"proxy"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "61570146b6102468475fbf727eb574d0beefd15458664c18c6e7dbf465b77fb4",
"md5": "0d2590367863a0de3030f856d4530009",
"sha256": "df626f0756e62fc89e592c86d468e2a4bff9efe93cfac2a624252b6165a8a6de"
},
"downloads": -1,
"filename": "magic_api_proxy-0.1.14-py3-none-any.whl",
"has_sig": false,
"md5_digest": "0d2590367863a0de3030f856d4530009",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.6",
"size": 21508,
"upload_time": "2023-03-22T21:48:09",
"upload_time_iso_8601": "2023-03-22T21:48:09.369748Z",
"url": "https://files.pythonhosted.org/packages/61/57/0146b6102468475fbf727eb574d0beefd15458664c18c6e7dbf465b77fb4/magic_api_proxy-0.1.14-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "de99a9ceca12836b8ca24667a2132c85beca704191dcfaf4de5103c35f94188f",
"md5": "41dccd3384cb05af38a7362258735950",
"sha256": "a152f14d62e631d440fa94412eb5b931b8172d72d0bdd6ebf501c5cc81a0210a"
},
"downloads": -1,
"filename": "magic-api-proxy-0.1.14.tar.gz",
"has_sig": false,
"md5_digest": "41dccd3384cb05af38a7362258735950",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.6",
"size": 18118,
"upload_time": "2023-03-22T21:48:11",
"upload_time_iso_8601": "2023-03-22T21:48:11.030967Z",
"url": "https://files.pythonhosted.org/packages/de/99/a9ceca12836b8ca24667a2132c85beca704191dcfaf4de5103c35f94188f/magic-api-proxy-0.1.14.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-03-22 21:48:11",
"github": true,
"gitlab": false,
"bitbucket": false,
"github_user": "rienafairefr",
"github_project": "magic-api-proxy",
"travis_ci": false,
"coveralls": true,
"github_actions": true,
"requirements": [],
"lcname": "magic-api-proxy"
}