Custom App with Reverse Proxy
Introduction
The Groove.id proxy is a small application that will sit in front of your application. It will receive requests for your app, make sure the users are properly identified, and pass the request on to your application.

Diagram
In a typical scenario you will run the proxy on the same host that runs your application. The proxy listens for incoming requests, makes sure they are from valid users, and then passes those requests on to your application.
The Groove.id reverse proxy sits in front of your custom web application and filters incoming requests. By default it makes sure that all incoming requests have been authenticated using Groove.id before your application even sees the request.
Using this model, you don’t have to worry about the nitty-gritty of correctly implementing authentication protocols, and your application is protected from unauthenticated requests.
Your application can then inspect the request headers to determine which user has been authenticated and collect other biographical information.
Getting Started
In the Groove.id console, create a new proxy application.
If you haven’t already, install the client software with
curl -sL https://signin.example.com/get.sh | bash

Setup
Copy the token parameter and pass it the the proxy:
$ grooveid proxy --token=$YOUR_TOKEN
By default the proxy will listen on tcp/443 and tcp/80 and will proxy requests to localhost:8000. It will automatically obtain a TLS certificate from Lets Encrypt if possible.
Handling Requests
The proxy will ensure that each request comes from a valid, authenticated user. Your upstream application receives information about the remote user via HTTP headers that are added to the request. An example request might look like:
Authorization: Basic cGdAaW5pdGVjaC5iaXo6
X-Forwarded-For: 127.0.0.1
X-Grooveid-Access-Check: http://myapp.example.com:8000/__grooveid/check_access?pt=HvLhvlczrbZD9v
X-Grooveid-Email: pg@initech.biz
X-Grooveid-Full-Name: Peter Gibbons
X-Grooveid-Session-Expires: Fri, 27 Jul 2018 16:27:22 GMT
X-Grooveid-User-Name: pg
X-Grooveid-User: OtczVCbP71qDGQ
X-Grooveid-Auth-Type: session
X-Remote-User: pg@initech.biz
The headers added to the request are:
X-Grooveid-User-Name
- the unix user name of the remote user.X-Grooveid-Email
- the user’s email address. (also included asX-Remote-User
)X-Grooveid-Full-Name
- the user’s full nameX-Grooveid-User
- a globally unique identifier for the user which will remain unchanged even if the email address or user name changes.X-Grooveid-Session-Expires
- The time when the user’s session expiresX-Grooveid-Auth-Type
- The kind of proof that was provided.bearer
means that an API key was used.session
means that a short-lived signed cookie corresponding to a new or existing session was presented.X-Forwarded-For
- the remote address of the requestX-Grooveid-Access-Check
- The URL for checking access during the request.Authorization
- a synthetic basic authorization header where the username is the user’s email address and the password is blank.
Access Check
The upstream server receives a URL in the X-Grooveid-Access-Check
request header. During the request, you may query this URL to determine if the remote user is a member of a particular group. An example request:
POST /__grooveid/check_access?pt=HvLhvlczrbZD9v HTTP/1.1
Host: myapp.example.com:8000
Content-Type: application/x-www-form-urlencoded
Content-Length: 114
group=eQPSVFjWJda1PF&group=om23cRgmpKt7A5&next=http%3A%2F%2Fmyapp.example.com%3A8000%2Fsome%2Fdeep%2Flink
The proxy server will respond with 200 Ok
if the remote user is a member of each of the groups specified. Otherwise, the proxy server will respond with 403 Forbidden
.
The forbidden response will include a Location
response header. If you direct the user to that URL they will be prompted to join or activate the group. When the process completes, the user will be sent to the url given in the next
parameter to the initial access check request.
The access check endpoint accepts the following parameters:
group
- which group to check (may be specified multiple times)next
- A URL to direct the user back to when the access request flow completes.op
- If “or” is specified then access to any of the groups is sufficient to allow access. If “and” is specified, then the user must be a member of all groups. The default is “and.”
Note: The access check URL is valid only while the request is being processed. After the request is complete, the access check URL is invalid.
This endpoint also returns a JSON body that includes the status information about each group:
[
{
"GroupID": "Z9Or13VAbDKGMP",
"StatusCode": 401,
"Location": "https://signin.initech.biz/groups/join?code=Group+Membership&data=..."
},
{
"GroupID": "uGHRZBr98fWqCw",
"StatusCode": 200
}
]
Note: When op=or
and the user is already an active member of one of the groups you provided, then because of the short-circuit evaluation, other groups will not be checked, and thus will not appear in the returned list. There is no short-circuit evaluation when op=and
is given.
Configuration
You can configure the proxy with a configuration file, with environment variables, or command line flags.
Example configuration file:
[proxy]
listen = :443
tls = on
cert = /var/secrets/tls.cert
key = /var/secrets/tls.key
upstream = "http://localhost:8000"
[auth]
token = "6b3xeo0mthu8wy.o9wpCxLMUtSKNF.OEI2YjESGkR01noWtjgH9CBv3bQH"
[redirect]
listen = :80
[path "/public"]
auth = none
[path "/private"]
auth = required
[path "/api"]
auth = optional
[path "/admin"]
auth = required
upstream = http://localhost:9999
Specify the configuration with the -C
flag, for example:
grooveid proxy -C /etc/grooveid-proxy.conf
The same configuration using the command line (and defaults):
grooveid proxy \
--listen :443 \
--cert /var/secrets/tls.cert \
--key /var/secrets/tls.key \
--upstream http://localhost:8000 \
--token 6b3xeo0mthu8wy.o9wpCxLMUtSKNF.OEI2YjESGkR01noWtjgH9CBv3bQH \
--redirect-listen :80 \
-c 'path_/public_auth=none' \
-c 'path_/private_auth=required' \
-c 'path_/api_auth=optional' \
-c 'path_/admin_auth=required' \
-c 'path_/admin_upstream=http://localhost:9999'
The same configuration using environment variables:
export GV_PROXY_LISTEN=:443
export GV_PROXY_CERT=/var/secrets/tls.cert
export GV_PROXY_KEY=/var/secrets/tls.key
export GV_PROXY_UPSTREAM=http://localhost:8000
export GV_AUTH_TOKEN=6b3xeo0mthu8wy.o9wpCxLMUtSKNF.OEI2YjESGkR01noWtjgH9CBv3bQH
export GV_REDIRECT_LISTEN=:80
export GV_PATH_/public_AUTH=none
export GV_PATH_/private_AUTH=required
export GV_PATH_/api_AUTH=optional
export GV_PATH_/admin_AUTH=required
export GV_PATH_/admin_UPSTREAM=http://localhost:9999
Settings
The following settings can be used to configure the proxy.
proxy.listen
Environment Variable: GV_PROXY_LISTEN
Commandline Flag: --listen
Default: :443
Specifies the address and port where the proxy interface should listen.
proxy.tls
Section: proxy
Name: tls
Environment Variable: GV_PROXY_TLS
Commandline Flag: --tls
Default: true
If true
then the proxy should listen for encrypted requests, otherwise the requests are expected to be plaintext.
proxy.cert
Section: proxy
Name: cert
Environment Variable: GV_PROXY_CERT
Commandline Flag: --cert
Default: empty
If this and proxy.key are specified then serve requests over TLS using the key and certificate. If not specified, then use the ACME protocol to obtain a certificate on demand.
proxy.key
Section: proxy
Name: key
Environment Variable: GV_PROXY_KEY
Commandline Flag: --key
Default: empty
If this and proxy.cert are specified then serve requests over TLS using the key and certificate. If not specified, then use the ACME protocol to obtain a certificate on demand.
proxy.name
Section: proxy
Name: name
Environment Variable: GV_PROXY_NAME
Commandline Flag: --name
Default: empty
Specifies the host name of the server. If not specified, then the server name is determined the first time a request is received.
proxy.auth
Section: proxy
Name: auth
Environment Variable: GV_PROXY_AUTH
Commandline Flag: --auth
Default: required
Specifies the default authentication mode for the server, which must be one of:
none
- no authentication is performed.optional
- when authentication information is present, verify it and pass it to the upstream server, but do not require it.required
- the remote user must be authenticated in order to pass a request to the upstream server.
Note: This setting may be overridden for a particular path prefix in a prefix section.
proxy.upstream
Section: proxy
Name: upstream
Environment Variable: GV_PROXY_UPSTREAM
Commandline Flag: --upstream
Default: http://localhost:8000
Specifies the default upstream server for the proxy.
Note: This setting may be overridden for a particular path prefix in a prefix section.
proxy.privateaddress
Section: proxy
Name: privateaddress
Environment Variable: GV_PROXY_PRIVATEADDRESS
Commandline Flag: --privateaddress
Default: (empty)
Specifies the address that the upstream service uses to make metadata requests, such as access checks, while processing the request. If not specified, the URL will be constructed from the inbound request. Change this setting if the URL in the X-Grooveid-Access
header is incorrect.
proxy.cookiekey
Section: proxy
Name: cookiekey
Environment Variable: GV_PROXY_COOKIEKEY
Commandline Flag: --cookiekey
Default: (empty)
Specifies the key used to sign session cookies. If not specified, a key will be generated at startup. This must be a PEM-encoded ECDSA private key on the P-256 curve.
proxy.cookiedomain
Section: proxy
Name: cookiedomain
Environment Variable: GV_PROXY_COOKIEDOMAIN
Default: (empty)
Specifies the domain to be used when issuing session cookies.
auth.token
Section: auth
Name: token
Environment Variable: GV_AUTH_TOKEN
Commandline Flag: --token
Default: (empty)
Specifies the Groove.id token that associates this proxy with an application in Groove.id. Get this value from the Groove.id console.
auth.server
Section: auth
Name: server
Environment Variable: GV_AUTH_SERVER
Commandline Flag: --auth-server
Default: https://auth.groove.id
Specifies the address of the Groove.id API server. Under normal circumstances, this should not need to change.
prefix.$prefix
You can override the default settings for a particular URL prefix by specifying a prefix
section. When processing a request, the longest prefix that matches is used.
Example:
[proxy]
auth = required
[prefix /public]
auth = none
[prefix /api]
auth = optional
prefix.$prefix.auth
Section: prefix
Subsection: a URL path prefix
Name: auth
Overrides the authentication mode specified by proxy.auth for this prefix.
prefix.$prefix.upstream
Section: prefix
Subsection: a URL path prefix
Name: upstream
Overrides the upstream server specified by proxy.upstream for this prefix.
redirect.listen
Section: redirect
Name: listen
Environment Variable: GV_REDIRECT_LISTEN
Commandline Flag: --redirect-listen
Default: :80
The redirector is used to redirect plaintext http requests to encrypted https requests. This option specified the address and port where the plaintext redirector should listen.
acme.server
Section: acme
Name: server
Environment Variable: GV_ACME_SERVER
Commandline Flag: --acme-server
Default: https://acme-v01.api.letsencrypt.org/directory
Specifies the ACME protocol server to use to issue certificates on demand. For testing use the Let’s Encrypt staging server https://acme-staging.api.letsencrypt.org/directory
acme.email
Section: acme
Name: email
Environment Variable: GV_ACME_EMAIL
Commandline Flag: --acme-email
Default: (empty)
Specifies the email address to use when registering a certificate using the ACME protocol. By default it derives the email address from the server name given in proxy.name.
API Access
You can use Groove.id API keys to access your application. To create an API key, select the API Keys tab, then Add.

Create an API key
Click the pencil icon next to Scopes and assign your new API key at least the user scope. Click Save.

Assign Scopes to the API key
You can specify the API key in the Authorization header, as the username or password in HTTP basic authentication.
Using the authorization header:
curl -H "Authorization: Bearer API_KEY https://myapp.example.com:4343/
GET / HTTP/1.1
Host: myapp.example.com
Authorization: Bearer API_KEY
Using the username field in basic authentication:
curl -u "API_KEY:" https://myapp.example.com:4343/