Authentication
Proc calls are authenticated with a secret key or authorization. Secret keys provide full access to your account, while authorizations provide fine-grained access control to specific abilities that you define up-front.
Client libraries handle authentication for you when a connection is created. If you're not using a client library, you
can pass the authorization through the authorization
header with a type of bearer
.
Setup
require "proc"
client = Proc.connect("PROCAUTH")
const Proc = require("@proc.dev/client");
const client = Proc.connect("PROCAUTH");
authorization=PROCAUTH
client.math.add.call(
1, value: 1
)
client.math.add.call(
1, {value: 1}
);
curl "https://proc.run/math/add?value=1" --silent \
--header "authorization: bearer $authorization" \
--header "content-type: application/json" \
--data '1'
2
Security Considerations
Secret keys provide unrestricted access to every proc endpoint. Exposing a secret key in any public way will allow someone to call any proc and access any persistent data in your account. Our recommendation is to only use secret keys to create authorizations with specific abilities.
Using Authorizations
Authorizations have no access by default and must be granted specific abilities at creation time. Their restrictive-by-default nature make limited authorizations safe to distribute in places they may become public, like in a web browser or mobile app. You can even configure authorizations to expire automatically, discussed more below.
Authorizations are created through the auth.create
endpoint.
Defining Abilities
Authorizations only have access to the abilities they are created with. You can specify one or more abilities through
the abilities
argument in the auth.create
proc. Each ability defines a package or proc that the authorization has
access to. For example, creating an authorization with abilities of ["type"]
grants access to all procs defined in
the type
package.
Setup
require "proc"
client = Proc.connect("PROCAUTH")
const Proc = require("@proc.dev/client");
const client = Proc.connect("PROCAUTH");
authorization=PROCAUTH
authorization = client.auth.create.call(
abilities: ["type"]
)
Proc.connect(authorization)["type.string.reverse"].call(
"hello"
)
let authorization = await client.auth.create.call(
null, {abilities: ["type"]}
);
await Proc.connect(authorization)["type.string.reverse"].call("hello");
authorization=$(curl https://proc.run/auth/create --silent \
--header "authorization: bearer $authorization" \
--header "content-type: application/vnd.proc+json" \
--header "accept: text/plain" \
--data '[["$$", "abilities", ["type"]]]')
curl "https://proc.run/type/string/reverse" --silent \
--header "authorization: bearer $authorization" \
--header "content-type: text/plain" \
--data 'hello'
olleh
Authorizations can be created with multiple abilities, providing fine-grained access control. For example, creating an
authorization with abilities of ["keyv.get", "keyv.scan"]
grants read-only access to the key-value store.
Setup
require "proc"
client = Proc.connect("PROCAUTH")
const Proc = require("@proc.dev/client");
const client = Proc.connect("PROCAUTH");
authorization=PROCAUTH
authorization = client.auth.create.call(
abilities: ["keyv.get", "keyv.scan"]
)
let authorization = await client.auth.create.call(
null, {abilities: ["keyv.get", "keyv.scan"]}
);
curl https://proc.run/auth/create --silent \
--header "authorization: bearer $authorization" \
--header "content-type: application/vnd.proc+json" \
--header "accept: text/plain" \
--data '[["$$", "abilities", ["keyv.get", "keyv.scan"]]]'
Proc returns an error if the authorization attempts to call a proc it has not been authorized to call.
Setup
require "proc"
client = Proc.connect("PROCAUTH")
const Proc = require("@proc.dev/client");
const client = Proc.connect("PROCAUTH");
authorization=PROCAUTH
limited = client.auth.create.call(
abilities: ["type"]
)
Proc.connect(limited)["keyv.get"].call(
"some_key"
)
let limited = await client.auth.create.call(
null, {abilities: ["type"]}
);
await Proc.connect(limited).keyv.get.call(
"some_key"
);
limited=$(curl https://proc.run/auth/create --silent \
--header "authorization: bearer $authorization" \
--header "content-type: application/vnd.proc+json" \
--header "accept: text/plain" \
--data '[["$$", "abilities", ["type"]]]')
curl "https://proc.run/keyv/get" --silent \
--header "authorization: bearer $limited" \
--header "content-type: text/plain" \
--data 'some_key'
authorization does not have the ability to access proc keyv.get
Key-Value Store Capabilities
The
keyv
package allows abilities to be defined for specific buckets and prefixes—read more in the key-value docs.
Insecure Abilities
Some abilities are dangerous to grant to an authorization. Here are some examples:
- Granting
auth.create
would allow the authorization to create new authorizations with any abilities. The newly created authorizations could access any part of your account. - Granting
proc.update
would allow the authorization to arbitrarily update stored procs, potentially injecting harmful behavior into your account.
By default, attempting to create an insecure authorization causes an error. You can override this behavior by passing
the insecure
argument with a value of true
when calling auth.create
.
Expiring Authorizations
Authorizations do not expire by default. You can create an authentication that expires at a future point in time by
passing a timestamp through the expiry
argument to auth.create
.
Setup
require "proc"
client = Proc.connect("PROCAUTH")
const Proc = require("@proc.dev/client");
const client = Proc.connect("PROCAUTH");
authorization=PROCAUTH
authorization = client.auth.create.call(
abilities: ["type"], expiry: 1933803200
)
let authorization = await client.auth.create.call(
null, {abilities: ["type"], expiry: 1933803200}
);
curl https://proc.run/auth/create?expiry=1933803200 --silent \
--header "authorization: bearer $authorization" \
--header "content-type: application/vnd.proc+json" \
--header "accept: text/plain" \
--data '[["$$", "abilities", ["type"]]]'
To create an authorization that expires in some number of seconds, you can create an authorization with a ttl.
Setup
require "proc"
client = Proc.connect("PROCAUTH")
const Proc = require("@proc.dev/client");
const client = Proc.connect("PROCAUTH");
authorization=PROCAUTH
authorization = client.auth.create.call(
abilities: ["type"], ttl: 60
)
let authorization = await client.auth.create.call(
null, {abilities: ["type"], ttl: 60}
);
curl https://proc.run/auth/create?ttl=60 --silent \
--header "authorization: bearer $authorization" \
--header "content-type: application/vnd.proc+json" \
--header "accept: text/plain" \
--data '[["$$", "abilities", ["type"]]]'
Managing Secrets
Secret keys are managed through your Proc Account Settings. You can create secrets or roll existing secrets.
Rolling Secrets
For an extra layer of security, secrets should be rolled from time to time. When you decide to roll a secret you can choose whether it should be rolled immediately or at a future point in time.
Note that authorizations and cursors are tied to the secret they are created with—when a rolled secret expires, all authorizations and cursors created from the expired secret will become invalid.
Stuck? Want to chat about an idea? Join the community on Discord.