OAuth 2.0 Auth Middleware¶
Daml includes an implementation of an auth middleware that supports OAuth 2.0 Authorization Code Grant. The implementation aims to be configurable to support different OAuth 2.0 providers and to allow custom mappings from Daml ledger claims to OAuth 2.0 scopes.
OAuth 2.0 Configuration¶
RFC 6749 specifies that OAuth 2.0 providers offer two endpoints: The authorization endpoint and the token endpoint. The URIs for these endpoints can be configured independently using the following fields:
oauth-auth
oauth-token
The OAuth 2.0 provider may require that the application identify itself using a client identifier and client secret. These can be specified using the following environment variables:
DAML_CLIENT_ID
DAML_CLIENT_SECRET
The auth middleware assumes that the OAuth 2.0 provider issues JWT access tokens.
The /auth
endpoint will validate the token, if available, and ensure that it grants the requested claims.
The auth middleware accepts the same command-line flags as the Daml Sandbox to define the public key for token validation.
Request Templates¶
The exact format of OAuth 2.0 requests may vary between providers. Furthermore, the mapping from Daml ledger claims to OAuth 2.0 scopes is defined by the IAM operator. For that reason OAuth 2.0 requests made by auth middleware can be configured using user defined Jsonnet templates. Templates are parameterized configurations expressed as top-level functions.
Authorization Request¶
This template defines the format of the Authorization request. Use the following config field to use a custom template:
oauth-auth-template
Arguments¶
The template will be passed the following arguments:
config
(object)clientId
(string) the OAuth 2.0 client identifierclientSecret
(string) the OAuth 2.0 client secret
request
(object)claims
(object) the requested claimsadmin
(bool)applicationId
(string or null)actAs
(list of string)readAs
(list of string)
redirectUri
(string)state
(string)
Returns¶
The query parameters for the authorization endpoint encoded as an object with string values.
Example¶
local scope(claims) =
local admin = if claims.admin then "admin";
local applicationId = if claims.applicationId != null then "applicationId:" + claims.applicationId;
local actAs = std.map(function(p) "actAs:" + p, claims.actAs);
local readAs = std.map(function(p) "readAs:" + p, claims.readAs);
[admin, applicationId] + actAs + readAs;
function(config, request) {
"audience": "https://daml.com/ledger-api",
"client_id": config.clientId,
"redirect_uri": request.redirectUri,
"response_type": "code",
"scope": std.join(" ", ["offline_access"] + scope(request.claims)),
"state": request.state,
}
Token Request¶
This template defines the format of the Token request. Use the following config field to use a custom template:
oauth-token-template
Arguments¶
The template will be passed the following arguments:
config
(object)clientId
(string) the OAuth 2.0 client identifierclientSecret
(string) the OAuth 2.0 client secret
request
(object)code
(string)redirectUri
(string)
Returns¶
The request parameters for the token endpoint encoded as an object with string values.
Example¶
function(config, request) {
"client_id": config.clientId,
"client_secret": config.clientSecret,
"code": request.code,
"grant_type": "authorization_code",
"redirect_uri": request.redirectUri,
}
Refresh Request¶
This template defines the format of the Refresh request. Use the following config field to use a custom template:
oauth-refresh-template
Arguments¶
The template will be passed the following arguments:
config
(object)clientId
(string) the OAuth 2.0 client identifierclientSecret
(string) the OAuth 2.0 client secret
request
(object)refreshToken
(string)
Returns¶
The request parameters for the authorization endpoint encoded as an object with string values.
Example¶
function(config, request) {
"client_id": config.clientId,
"client_secret": config.clientSecret,
"grant_type": "refresh_code",
"refresh_token": request.refreshToken,
}
Deployment Notes¶
The auth middleware API relies on sharing cookies between the auth middleware and the Daml application.
One way to enable this is to expose the auth middleware and the Daml application under the same domain, e.g. through a reverse proxy.
Note that you will need to specify the external callback URI in that case using the --callback
command-line flag.
For example, assuming the following nginx configuration snippet:
http {
server {
server_name example.com
location /auth/ {
proxy_pass http://localhost:3000/;
}
}
}
You would invoke the OAuth 2.0 auth middleware with the following flags:
oauth2-middleware \
--config oauth-middleware.conf
The required config would look like
{
// Environment variables:
// DAML_CLIENT_ID The OAuth2 client-id - must not be empty
// DAML_CLIENT_SECRET The OAuth2 client-secret - must not be empty
client-id = ${DAML_CLIENT_ID}
client-secret = ${DAML_CLIENT_SECRET}
//IP address that OAuth2 Middleware service listens on. Defaults to 127.0.0.1.
address = "127.0.0.1"
//OAuth2 Middleware service port number. Defaults to 3000. A port number of 0 will let the system pick an ephemeral port. Consider specifying `--port-file` option with port number 0.
port = 3000
//URI to the auth middleware's callback endpoint `/cb`. By default constructed from the incoming login request.
callback-uri = "https://example.com/auth/cb"
//Maximum number of simultaneously pending login requests. Requests will be denied when exceeded until earlier requests have been completed or timed out.
max-login-requests = 250
//Login request timeout. Requests will be evicted if the callback endpoint receives no corresponding request in time.
login-timeout = 60s
//Enable the Secure attribute on the cookie that stores the token. Defaults to true. Only disable this for testing and development purposes.
cookie-secure = "true"
//URI of the OAuth2 authorization endpoint
oauth-auth="https://oauth2-provider.com/auth_uri"
//URI of the OAuth2 token endpoint
oauth-token="https://oauth2-provider.com/token_uri"
//OAuth2 authorization request Jsonnet template
oauth-auth-template="file://path/oauth/auth/template"
//OAuth2 token request Jsonnet template
oauth-token-template = "file://path/oauth/token/template"
//OAuth2 refresh request Jsonnet template
oauth-refresh-template = "file://path/oauth/refresh/template"
// Enables JWT-based authorization, where the JWT is signed by one of the below Jwt based token verifiers
token-verifier {
// type can be rs256-crt, es256-crt, es512-crt or rs256-jwks
type = "rs256-jwks"
// X509 certificate file (.crt)/JWKS url from where the public key is loaded
uri = "https://example.com/.well-known/jwks.json"
}
}
The oauth2-middleware can also be started using cli-args.
Note
Configuration file is the recommended way to run oauth2-middleware, running via cli-args is now deprecated
oauth2-middleware \
--callback https://example.com/auth/cb \
--address localhost \
--http-port 3000 \
--oauth-auth https://oauth2-provider.com/auth_uri \
--oauth-token https://oauth2-provider.com/token_uri \
--auth-jwt-rs256-jwks https://example.com/.well-known/jwks.json
Some browsers reject Secure
cookies on unencrypted connections even on localhost.
You can pass the command-line flag --cookie-secure no
for testing and development on localhost to avoid this.