Proxied Authentication

Posit Connect supports proxied authentication. This allows an external system to intercept requests and handle the authentication of users visiting the Posit Connect dashboard, or the applications it hosts.

Configuration Example

Note

The ProxyAuth configuration appendix contains information about each ProxyAuth configuration option.

[Authentication]
Provider = "proxy"

[Server]
Address = "https://example.com/apps/posit-connect"

[ProxyAuth]
LoginURL = "https://example.com/auth/login"
LogoutURL = "https://example.com/auth/logout"
; This configuration only requires the proxy to send
; the default header "X-Auth-Username" with a valid
; username for authentication purposes.  More headers
; can be sent by the proxy to complement the user profile.
; Uncomment the following as needed:
;UniqueIdHeader = "X-Auth-ID"
;UsernameHeader = "X-Auth-Custom-Username"
;FirstNameHeader = "X-Auth-First-Name"
;LastNameHeader = "X-Auth-Last-Name"
;EmailHeader = "X-Auth-Email"
;RoleHeader = "X-Auth-RSC-Role"
;GroupsHeader = "X-Auth-Groups"
; Enable this for a better user experience if using groups,
; unless managing a large number of groups is a concern:
;GroupsAutoProvision = true

; When troubleshooting a proxied authentication problem, more
; verbose logging is produced by uncommenting the following line:
;Logging = true

How this Works

A service (like NGINX, for example) runs as your customized authentication server. It is responsible for intercepting all requests to Posit Connect and performing the required authentication and authorization. Requests from authenticated users will have custom HTTP headers added before the request is proxied through to Posit Connect. The HTTP headers will contain the username and other identifying information of that visitor. Posit Connect will take the values from the HTTP headers and treat the traffic as the user specified in the headers.

We have no means of validating that this HTTP header was added by your authentication server and not by the user directly. It is very important from a security perspective that network access to the Posit Connect server is properly limited by a firewall or other network restriction. All access to Posit Connect must be proxied through your authentication server.

Important

The HTTP header identifying the user should never be set by the requester. In all cases, your authentication server should delete that header if it exists before authenticating the user and adding the header itself. Posit Connect will return a generic authentication failure if duplicate authentication headers are provided.

Deployment from the RStudio IDE

Deploying from the RStudio IDE is a unique situation. The IDE uses the R package rsconnect to obtain deployment credentials from Posit Connect. Those credentials are used to sign deployment requests. The minimum required version of rsconnect that supports proxied authentication is 0.8.7.

Deployment requests are signed with credentials obtained during an earlier, authenticated session, and should pass through your proxy without alteration.

The X-Auth-Token header identifies deployment requests. When the X-Auth-Token header is present, the request should be allowed to pass through your proxy without attempting to authenticate the user. Further, the following three headers are used in the deployment process and should not be edited or removed by your proxy.

  • X-Auth-Token
  • X-Auth-Signature
  • X-Content-Checksum
Tip

Alternatively, specifying a Login URL for your proxy can simplify your proxy configuration and make the deployment from the RStudio IDE easier. By using this option, Posit Connect itself will determine the need of authentication without requiring the proxy to intercept the headers listed above.

Using the Posit Connect Server API

The Authorization header should allow traffic to pass through the proxy without attempting to authenticate the user when:

  • The Posit Connect Server API is being used.
  • Posit Connect is serving hosted APIs (e.g. Plumber, FastAPI)
Note

Look for a value containing Key followed by the API key for a more specific match of the Authorization header used by Posit Connect.

Tip

Alternatively, specifying a Login URL for your proxy can simplify your proxy configuration and make using the Posit Connect Server API easier. By using this option, Posit Connect itself will determine the need of authentication without requiring the proxy to intercept the Authorization header.

If your proxy uses the Authorization header already, then it is possible for Connect to use the X-RSC-Authorization header instead. If both headers are present, the X-RSC-Authorization header takes higher priority and the Authorization header will be ignored.

Basic Configuration

To configure Posit Connect to use proxied authentication, set Authentication.Provider to proxy.

; /etc/rstudio-connect/rstudio-connect.gcfg
[Authentication]
Provider = "proxy"

Proxied authentication requires that you set Server.Address to point at your proxy server. If you do not configure Server.Address, the browser may not have all its requests routed through your authenticating proxy. See Editing the Configuration File for more information about Server.Address.

; /etc/rstudio-connect/rstudio-connect.gcfg
[Server]
Address = "https://myproxy.company.com/"

You can customize the name of the header that your authentication server will send upon a successful authentication. By default, this key name is X-Auth-Username.

; /etc/rstudio-connect/rstudio-connect.gcfg
[ProxyAuth]
UsernameHeader = "X-Auth-Username"

Posit Connect can also be configured to receive more complete user profile information from the proxy via additional headers.

; /etc/rstudio-connect/rstudio-connect.gcfg
[ProxyAuth]
UsernameHeader = "X-Auth-Username"
FirstNameHeader = "X-Auth-First-Name"
LastNameHeader = "X-Auth-Last-Name"
EmailHeader = "X-Auth-Email"

Defining these headers effects which user profile fields are editable. See more below

Specifying Login & Logout URLs

Login URL

In most cases, the authentication and the proxy will not let users reach Posit Connect unless they have a valid session. However, in some cases you may wish to let users visit some content without authentication; allowing Posit Connect to control when login is required.

If your proxy has a known endpoint that users should visit to open a session, you can configure the endpoint URL in Posit Connect with the configuration option ProxyAuth.LoginURL.

; /etc/rstudio-connect/rstudio-connect.gcfg
[ProxyAuth]
LoginURL = "https://proxy/login"

It is important to note that Posit Connect will take this URL as-is and it will redirect to it when users click the “Log In” link in its Dashboard.

Proxies should consider the Referer header during this redirect. It may contain the URL originally visited by the user in Posit Connect and the proxy may want to refer users back to this location after authentication.

Note

The “Log Out” in the Dashboard is made visible when ProxyAuth.LoginURL is defined. This behavior is considered a convenience, and the act of logging out will only take users back to the configured login URL. It is up to the proxy to determine if this action is capable of invalidating the session.

Logout URL

Since authentication is controlled by the proxy, Posit Connect has no means for finishing the user session on the proxy, and steps must be taken outside of Posit Connect in order to close the session.

If your proxy has a known endpoint that users should visit to close a session, you can configure the endpoint URL in Posit Connect with the configuration option ProxyAuth.LogoutURL.

; /etc/rstudio-connect/rstudio-connect.gcfg
[ProxyAuth]
LogoutURL = "https://proxy/logout"

It is important to note that Posit Connect will take this URL as-is and place it in the “Log Out” link in its Dashboard. Clicking the link will take the browser directly to the configured logout URL. It will not be a redirect.

Note

No information about the current logged-in user will be provided, the proxy must be able to determine this based on the context (e.g., cookies).

User Provisioning

Users are created in Posit Connect upon their first successful login attempt. Users may also be created ahead of their first login by adding them as users via the Posit Connect Server API.

Note

Users created via the API must match exactly the identifier expected to be received through the authentication proxy. By default, this identifier is the username, but it’s possible to employ a separate unique identifier. See more below on the section on Unique ID.

The authentication happens entirely in the proxy placed in front of Posit Connect which expects to receive from the former a HTTP header containing the identifier of the authenticated remote user account.

Register on First Login

By default, users can be created in Posit Connect upon their first successful login attempt. Accounts will be created with the role specified in the Authorization.DefaultUserRole setting (see User Roles) or via User Role Mapping if configured. Otherwise, the role may be specified as the user is created via the Posit Connect Server API.

Disabling Register on First Login

If you wish to disable this feature, set the configuration setting ProxyAuth.RegisterOnFirstLogin to false.

; /etc/rstudio-connect/rstudio-connect.gcfg
[ProxyAuth]
RegisterOnFirstLogin = false
Important

Using this option requires users to be exclusively created via the Posit Connect Server API.

Usernames

Usernames in proxied authentication may or may not be unique depending on the configuration. This flexibility exists to adapt to the various authentication mechanisms that could be driving the proxied authentication.

Posit Connect imposes some additional restrictions on the usernames it supports:

  • The following values are prohibited: connect, apps, users, groups, setpassword, user-completion, confirm, recent, reports, plots, unpublished, settings, metrics, tokens, help, login, welcome, register, resetpassword, content
Warning

By default, usernames are the user identity which is unique and immutable. As such, changes to the username will result in new user created in Posit Connect.

Tip

If you wish to be able to update usernames over time while maintaining a single account for each user, a different form of unique user identity must be provided via the proxy headers. See Unique ID below.

Unique ID

The setting ProxyAuth.UniqueIdHeader determines which header holds the user identity. It’s important that the user identity sent over this header by the proxy be:

  • Unique: It is extremely important that different users do not have the same identity.

  • Persistent: Ideally this identity must not be attached to the username, email or names, since those may change over time. Values based on UUID/GUID are a great options if your authentication system provides them.

When configured this way, usernames provided by the proxy are not required to be unique.

Tip

Duplicate usernames may have adverse affects on content that tracks the user credentials. Please refer to the Credentials for Content in the Advanced Users and Group Topics appendix for alternatives under this condition.

Note

The RStudio IDE does not support duplicate usernames when publishing to the same Posit Connect host. However, it is unlikely that two users with the same usernames will be sharing the same IDE account or workstation.

Note

ProxyAuth.UniqueIdHeader also enables the Posit Connect Server API to accept the field unique_id for creating new users. This value must match the value sent by the proxy via headers. Internally in Connect, the UniqueID is stored encoded as a Base64 value. Once the user is created, the Posit Connect identity (guid) should be used for subsequent API operations with that user.

Important

Existing customers willing to enable the ProxyAuth.UniqueIdHeader MUST first update all users to the new identity before configuring the setting. The usermanager CLI tool can help in this migration. See the User Management CLI appendix.

Generated Usernames

When the ProxyAuth.UniqueIdHeader option is configured, you must include either the ProxyAuth.UsernameHeader or the ProxyAuth.EmailHeader option (or both) in your configuration. If you do not configure the username attribute, Posit Connect will create a new unique username for a user the first time that user logs in. The username will be derived from the user’s email address, without the domain, adding a numeric suffix as needed for uniqueness if necessary.

These generated usernames can later be modified by the users themselves or by an administrator as long as they remain unique. Posit Connect will refuse to change the username otherwise.

Note

Switching between configurations where duplicate usernames are possible to one where the usernames are unique is strongly discouraged. If such change is necessary, be sure to make usernames unique by using the usermanager CLI tool before restarting Posit Connect with the new configuration. See the User Management CLI appendix for more information.

Editing User Attributes

User profile fields sent by the proxy are not editable in Posit Connect.

Note

A non-editable field can be forcefully updated before a login via the usermanager CLI tool. See the User Management CLI appendix.

The user’s first name, last name, and email address are considered editable only if not provided by the proxy via configured headers. The setting Authorization.UserInfoEditableBy has a default value of AdminAndSelf, permitting users and administrators to manage these user profile attributes. Configure Authorization.UserInfoEditableBy with Admin if profile editing should be restricted to administrators.

Tip

It is recommended that if you disable ProxyAuth.RegisterOnFirstLogin with a value of false, that you also configure Authorization.UserInfoEditableBy to Admin. A value of Admin means that users created by the administrator cannot be changed by non-administrators.

Note

Usernames are only editable when a Unique ID is used with Generated Usernames.

Editing User Roles

User roles are only editable in Posit Connect if Automatic User Role Mapping is not configured, and the proxy authentication provider is not configured to send roles in as part of the user profile.

Automatic User Role Mapping

Posit Connect offers ways to map user information to valid roles when users login. This can be done with roles defined as part of the user profile or via group memberships.

Using Group Memberships

Important

This option does not work with Locally Managed Groups.

Use the configuration option Authorization.UserRoleGroupMapping to enable user role mapping via groups.

Warning

When group mapping is enabled, configuration options to receive roles from the authentication provider as part of the user profile information will be ignored and Posit Connect will fail to start if Authorization.UserRoleMapping is also enabled.

When enabled, the configuration options Authorization.ViewerRoleMapping, Authorization.PublisherRoleMapping, and Authorization.AdministratorRoleMapping will refer to groups.

In the following example group names are used. Viewer mapping is purposely left out so that the remaining of the users will be assigned the based on the option Authorization.DefaultUserRole which defaults to viewer.

; /etc/rstudio-connect/rstudio-connect.gcfg
[Authorization]
UserRoleGroupMapping = true
PublisherRoleMapping = "Developers"
AdministratorRoleMapping = "Dev-Leaders"
AdministratorRoleMapping = "IT-Administrators"
Note

When Groups By Unique ID are used, the role mapping should be based on the groups’ Unique IDs instead of their names.

Using User Profile Roles

You can configure Posit Connect to automatically define user roles based on header values sent by the proxy.

Use the configuration option Authorization.UserRoleMapping to enable user role mapping.

The ProxyAuth.RoleHeader configuration option should also be defined to receive role information as part of the user profile.

Note

User roles can be used directly from your authentication provider without the need of mapping values as long as it only returns the values of viewer, publisher and administrator to define roles in Posit Connect.

Note

Invalid role values are defaulted to value of Authorization.DefaultUserRole and the issue is reported in the logs if debug logging is enabled.

When mapping is enabled, each role can be mapped to one or more values specific to your organization using the configuration options Authorization.ViewerRoleMapping, Authorization.PublisherRoleMapping, and Authorization.AdministratorRoleMapping.

In the following example the authentication provider returns department names:

; /etc/rstudio-connect/rstudio-connect.gcfg
[Authorization]
UserRoleMapping = true
ViewerRoleMapping = "HR"
ViewerRoleMapping = "Marketing"
PublisherRoleMapping = "Engineering"
AdministratorRoleMapping = "IT"

Multiple User Role Mappings

When there are multiple matches between the configured mapping and the user or group information sent by the authentication provider, the role with the most privileges is selected. This behavior makes it easy to promote users to a new role.

Note

If there are concerns about security, a more restrictive behavior can be used in these scenarios with the configuration option Authorization.UserRoleMappingRestrictive. When enabled, it will cause the least privileged role to be selected.

Group Membership Management

Posit Connect can be configured to automatically assign users to existing groups according to the list of group names sent by your proxy. For every login attempt the list of group names received will be compared with the current memberships the user has, adding the user as a member of newly listed groups and removing the user from groups no longer listed.

Tip

If your proxy is not capable of sending user groups, it is still possible to use Locally Managed Groups in Posit Connect.

The setting ProxyAuth.GroupsHeader defines the name of the header containing the names of the groups the authenticating user is member of.

Note

Your authentication provider may send the groups’ identifiers instead of their names during login. See more below in Matching Groups’ Identifiers.

By default, it is expected that multiple groups names will come as separate occurrences of the same header, for example:

; /etc/rstudio-connect/rstudio-connect.gcfg
[ProxyAuth]
GroupsHeader = "X-Auth-Groups"

HTTP Request:

X-Auth-Groups: Engineering
X-Auth-Groups: Managers
...

However, it is also possible to send group names in a single header. In this case, the group names in the header value must be sent as a separated list. Use the setting ProxyAuth.GroupsHeaderSeparator to enable this behavior and set which character should be used to split the group names.

For example:

; /etc/rstudio-connect/rstudio-connect.gcfg
[ProxyAuth]
GroupsHeader = "X-Auth-Groups"
GroupsHeaderSeparator = "|"

HTTP Request:

X-Auth-Groups: Engineering|Managers|...
Note

Certain characters cannot be used as separators since they are prohibited in HTTP headers. The RFC 7230 defines those.

Manual Group Provisioning

Admins may use the “People” tab within the Posit Connect dashboard to “add” references to groups from the proxy. Group membership of Posit Connect users will be tracked for only these groups and not the entire list of groups that are returned from your proxy.

Tip

This is the default behavior, and a good option when the Posit Connect users are associated with a large number of groups, but only some of them are useful for content access control purposes.

Warning

Care should be taken when removing groups via “people” in the dashboard or via Connect Server API. Removing a group will also remove all associations between the group being removed and existing content.

Automatic Group Provisioning

In addition to memberships, Posit Connect can also be configured to automatically provision (create) new groups according to the list of group names sent by the proxy for the user. This can be enabled by using ProxyAuth.GroupsAutoProvision.

This means that groups not yet present will be created in Posit Connect for a user when the user logs in. These groups remain provisioned indefinitely, even after the last member has been removed, so that any access to content is preserved for a future member of those groups.

Tip

Removing stale or unused groups can be done via the dashboard, via the Posit Connect Server API, or ultimately via the usermanager CLI.

Switching Between Manual and Automatic Group Provisioning

Groups created by automatic provisioning do not have owners while any groups created manually or via the Connect Server API are always associated with a user.

Posit Connect will issue a warning on startup if the ownership of the existing groups does not match the provider configuration.

In these situations, either the group needs to be removed or group ownership needs to be adjusted. This can be done with the usermanager CLI tool with the alter command using the --new-owner or --drop-owner switches.

The goal is that all groups automatically provisioned should be assigned an owner if you intend to manage them in Posit Connect. Conversely if you intend to have all groups managed by the authentication provider their owners should be removed. Also, you should remove any groups that do not make sense in the new configuration and this can be done via the Posit Connect dashboard, the Connect Server API or the usermanager. See the User management CLI appendix.

Locally Managed Groups

You can still use groups in Posit Connect if you decide to not configure support for groups sent by the proxy.

Important

Locally managed groups have no relation with groups that may be present in the authentication mechanism driving the proxy.

These groups are local to Posit Connect, they can be created via the Dashboard or via the Connect Server API. Group memberships must also be managed using the same means.

Tip

If you do not want groups at all in Posit Connect, set the Authorization.UserGroups configuration option to false.

Matching Groups’ Identifiers

By default, Posit Connect will match the list of groups sent by the proxy against the names of the groups that exist in Posit Connect. Some authentication engines behind the proxy may not send group names, and instead send their unique identifiers (such as GUIDs).

Groups by Name

When your proxy sends group names, the default behavior of Posit Connect to match groups using a case-sensitive string comparison can be used.

Note

If groups are renamed within the authentication engine behind the proxy, they will be recognized as new groups as they are received by Posit Connect. Depending on the setting for ProxyAuth.GroupsAutoProvision, these new groups will either be added or ignored. In no circumstances will the old group be renamed or removed from content ACLs. You can still rename a group in Posit Connect to match the group name in your proxy to preserve all associations with content. If a duplicate group with the same name was created by automatic provisioning, this new group must be removed first.

Groups by Unique ID

To support the scenario where your proxy sends unique identifiers for groups rather than their names, Posit Connect can be configured to match these identifiers by using the setting ProxyAuth.GroupsByUniqueId.

Warning

This is considered to be an advanced feature in Posit Connect. Identifying groups by an identifier other than their name requires the use of the Posit Connect Server API for all group management workflows. The Posit Connect Dashboard does not allow group management in this scenario, except by the association of the group with some content, which is still possible.

A group identified by a unique identifier must be provisioned within Posit Connect using the Connect Server API. The API call allows for the association of the group’s unique_id (same one sent by the proxy during authentication) with a locally managed user friendly name, in general the same name as used in the authentication driving the proxy. Posit Connect will not enforce unique group names in this condition.

Tip

Duplicate group names may have adverse affects on content that tracks the user credentials. Please refer to the Credentials for Content in the Advanced Users and Group Topics appendix for alternatives under this condition.

Important

When ProxyAuth.GroupsByUniqueId is enabled, SAML.GroupsAutoProvision can NOT !be enabled. This would lead to the creation of groups without meaningful names in Posit Connect given that the IdP would only be providing a Unique ID.

Switching Between Group Identities

Preferably, GroupsByUniqueId should be enabled before you have any groups in Posit Connect. If any groups have already been created and you wish to use this option, it is strongly recommended to run the usermanager --groups --normalize-ids command to make these existing groups functional under the new setting. See the User Management CLI appendix to learn more. The usermanager command above should also be run if you decide to disable GroupsByUniqueId in a later time.

Troubleshooting Proxied Authentication

When attempting to troubleshoot a problem relating to proxied authentication, you can enable more verbose logging with ProxyAuth.Logging:

; /etc/rstudio-connect/rstudio-connect.gcfg
[ProxyAuth]
Logging = true

All the contents of headers and the names of the cookies received with the authentication request will be logged. Cookies and headers used by Posit Connect will be logged as <internal>. External cookie values will be logged as <redacted>. If an external cookie comes without a value it will be logged as <empty>.

  • “Rejected insecure proxied authentication attempt” appears in the server logs, users cannot log in

    1. Ensure that the proxy is configured to delete the configured username, names, email and unique identity headers from incoming requests (X-Auth-Username by default).

    2. Ensure that users are connecting to Posit Connect by its proxy, and not directly to the server. As noted above, your network should be configured to make non-proxied connections to Posit Connect impossible.

  • Attempts to deploy to Posit Connect from the IDE fail because users are redirected to a Single Sign-On page.

    1. Ensure that the proxy is configured to pass through all requests that set the X-Auth-Token header.

    2. Ensure that the user has the rsconnect package with at least version 0.8.7 installed. If not, and if the package isn’t available from CRAN, it may be installed from the R console with:

      devtools::install_github('rstudio/rsconnect')

    See Deployment from the RStudio IDE.

  • Attempts to use the Connect Server API fail because users are redirected to a Single Sign-On page.

    1. Ensure that the proxy is configured to pass through all requests that set the Authentication header with a Key value.

    2. Ensure that the proxy is not blocking other headers that may be required by hosted APIs (e.g. Plumber, FastAPI)

    See Using the Posit Connect Server API.

Example Proxy Configuration

The following examples demonstrate how to intercept and re-route unauthenticated requests to Posit Connect, which is served via reverse-proxy at /rsconnect. The examples assume an authentication server is running at /auth which, upon successful authentication, will set a HTTP-only cookie named verified-user containing the username of the authenticated user and redirect the user back to Posit Connect via the URL specified in the url query parameter. A similar logic is applied to remaining examples that send additional user information.

Important

These examples are intended to aid with an initial configuration of Posit Connect behind an authenticating proxy. They are not recommended for production environments and have severe functional limitations (i.e., ' and ; are not accepted in values because the examples use plain text cookies) and offer no security at all. Customers are urged to adhere to the best security practices and recommended settings for their proxy.

All examples below are based on how to run a proxy in front of Posit Connect. See Running with a Proxy.

Note

These examples assume your proxy has no specific URLs for login and logout but there is indication after each example of what should be changed in the proxy configuration if these URLs are available and configured in Posit Connect with the options ProxyAuth.LoginURL and ProxyAuth.LogoutURL.

Basic configuration examples

The bare minimum to allow a user coming from an authentication proxy to enter Posit Connect. It assumes default values for the existing settings for proxied authentication. See Configuring Proxied Authentication.

These examples send traffic through the proxy if the verified-user cookie is present. The examples also allow traffic for deployments from the RStudio IDE or API use if the respective headers are present. See Using the Posit Connect Server API and Deployment from the RStudio IDE.

nginx

This is a basic configuration example using nginx.

map $http_upgrade $connection_upgrade {
  default upgrade;
  ""      close;
}

map $http_cookie $auth_username {
  default "";
  "~*verified-user=(?<username>[^;]+)" "$username";
}

map "$http_x_auth_token" $has_token {
    default "";
    "~.+" "token";
}

map "$http_authorization" $has_key {
    default "";
    "~Key .+" "key";
}

map "$auth_username:$has_token:$has_key" $requires_auth {
  default 0;
  "::" 1;
}

server {
  listen 80 default_server;

  location /rsconnect/ {

    # Redirect directly to authentication if the username is not
    # present. Needed if there is no login endpoint in the proxy.
    if ($requires_auth = 1) {
      return 307 $scheme://$host:$server_port/auth/login?url=$request_uri;
    }

    rewrite                    ^/rsconnect/(.*)$ /$1 break;
    proxy_pass                 http://posit-connect-host:3939;
    proxy_redirect             / /rsconnect/;
    proxy_pass_request_headers on;
    proxy_connect_timeout      5;
    proxy_http_version         1.1;
    proxy_buffering            off; # Required for XHR-streaming

    proxy_set_header           Upgrade $http_upgrade;
    proxy_set_header           Connection $connection_upgrade;
    proxy_set_header           X-RSC-Request $scheme://$host:$server_port$request_uri;
    proxy_set_header           X-Auth-Username $auth_username;
  }
}
Note

If you have configured ProxyAuth.LoginURL the authentication condition if ($requires_auth = 1) of the example above is no longer needed.

Apache HTTP Server

This is a basic configuration example using the Apache HTTP server.

RewriteEngine on

<VirtualHost *:80>
  SetEnvIf Cookie "verified-user=([^;]+)" AuthUsername=$1

  # Redirect directly to authentication if the username is not
  # present. Needed if there is no login endpoint in the proxy.
  <If "%{REQUEST_URI} !~ m#^/auth# && -z env('AuthUsername') && -z %{HTTP:X-Auth-Token} && %{HTTP:Authorization} !~ /Key .+/">
    Redirect 307 "%{REQUEST_SCHEME}://%{HTTP_HOST}/auth/login?url=%{REQUEST_URI}"
  </If>

  # store variable values with dummy rewrite rules
  RewriteRule . - [E=req_scheme:%{REQUEST_SCHEME}]
  RewriteRule . - [E=http_host:%{HTTP_HOST}]
  RewriteRule . - [E=req_uri:%{REQUEST_URI}]
  # set header with variables
  RequestHeader set X-RSC-Request "%{req_scheme}e://%{http_host}e%{req_uri}e"

  RewriteCond %{HTTP:Upgrade} websocket [NC]
  RewriteCond %{HTTP:Connection} upgrade [NC]
  RewriteRule ^/(.*) "ws://posit-connect-host:3939/$1" [P,L]

  <If "-n env('AuthUsername')">
    RequestHeader set X-Auth-Username "%{AuthUsername}e"
  </If>
  <Else>
    RequestHeader unset X-Auth-Username
  </Else>

  <Location />
    ProxyPass http://posit-connect-host:3939/ connectiontimeout=5
  </Location>
</VirtualHost>
Note

If you have configured ProxyAuth.LoginURL, the authentication condition <If "%{REQUEST_URI} of the example above is no longer needed.

Configuration examples with user profile support

These configurations extend the basic examples and add support for headers carrying user profile information, such as names and email. The names for the different headers must be also present in your Posit Connect configuration. See Configuring Proxied Authentication.

nginx

This is an nginx configuration example using headers to carry user profile information.

map $http_upgrade $connection_upgrade {
  default upgrade;
  ""      close;
}

map $http_cookie $auth_username {
  default "";
  "~*verified-user=(?<username>[^;]+)" "$username";
}

map $http_cookie $auth_firstname {
  default "";
  "~*proxyauth-as-first=(?<first>[^;]+)" "$first";
}

map $http_cookie $auth_lastname {
  default "";
  "~*proxyauth-as-last=(?<last>[^;]+)" "$last";
}

map $http_cookie $auth_email {
  default "";
  "~*proxyauth-as-email=(?<email>[^;]+)" "$email";
}

map "$http_x_auth_token" $has_token {
    default "";
    "~.+" "token";
}

map "$http_authorization" $has_key {
    default "";
    "~Key .+" "key";
}

map "$auth_username:$has_token:$has_key" $requires_auth {
  default 0;
  "::" 1;
}

server {
  listen 80 default_server;

  location /rsconnect/ {

    # Redirect directly to authentication if the username is not
    # present. Needed if there is no login endpoint in the proxy.
    if ($requires_auth = 1) {
      return 307 $scheme://$host:$server_port/auth/login?url=$request_uri;
    }

    rewrite                    ^/rsconnect/(.*)$ /$1 break;
    proxy_pass                 http://posit-connect-host:3939;
    proxy_redirect             / /rsconnect/;
    proxy_pass_request_headers on;
    proxy_connect_timeout      5;
    proxy_http_version         1.1;
    proxy_buffering            off; # Required for XHR-streaming

    proxy_set_header           Upgrade $http_upgrade;
    proxy_set_header           Connection $connection_upgrade;
    proxy_set_header           X-RSC-Request $scheme://$host:$server_port$request_uri;
    proxy_set_header           X-Auth-Username $auth_username;
    proxy_set_header           X-Auth-Firstname $auth_firstname;
    proxy_set_header           X-Auth-Lastname $auth_lastname;
    proxy_set_header           X-Auth-Email $auth_email;
  }
}
Tip

If you have configured ProxyAuth.LoginURL, the authentication condition if ($requires_auth = 1) of the example above is no longer needed.

Apache HTTP Server

This is an Apache HTTP server configuration example using headers to carry user profile information.

RewriteEngine on

<VirtualHost *:80>
  SetEnvIf Cookie "verified-user=([^;]+)" AuthUsername=$1
  SetEnvIf Cookie "proxyauth-as-first=([^;]+)" AuthFirstName=$1
  SetEnvIf Cookie "proxyauth-as-last=([^;]+)" AuthLastName=$1
  SetEnvIf Cookie "proxyauth-as-email=([^;]+)" AuthEmail=$1

  # Redirect directly to authentication if the username is not
  # present. Needed if there is no login endpoint in the proxy.
  <If "%{REQUEST_URI} !~ m#^/auth# && -z env('AuthUsername') && -z %{HTTP:X-Auth-Token} && %{HTTP:Authorization} !~ /Key .+/">
    Redirect 307 "%{REQUEST_SCHEME}://%{HTTP_HOST}/auth/login?url=%{REQUEST_URI}"
  </If>

  <If "-n env('AuthUsername')">
    RequestHeader set X-Auth-Username "%{AuthUsername}e"
  </If>
  <Else>
    RequestHeader unset X-Auth-Username
  </Else>
  <If "-n env('AuthFirstName')">
    RequestHeader set X-Auth-Firstname "%{AuthFirstName}e"
  </If>
  <Else>
    RequestHeader unset X-Auth-Firstname
  </Else>
  <If "-n env('AuthLastName')">
    RequestHeader set X-Auth-Lastname "%{AuthLastName}e"
  </If>
  <Else>
    RequestHeader unset X-Auth-Lastname
  </Else>
  <If "-n env('AuthEmail')">
    RequestHeader set X-Auth-Email "%{AuthEmail}e"
  </If>
  <Else>
    RequestHeader unset X-Auth-Email
  </Else>

  # store variable values with dummy rewrite rules
  RewriteRule . - [E=req_scheme:%{REQUEST_SCHEME}]
  RewriteRule . - [E=http_host:%{HTTP_HOST}]
  RewriteRule . - [E=req_uri:%{REQUEST_URI}]
  # set header with variables
  RequestHeader set X-RSC-Request "%{req_scheme}e://%{http_host}e%{req_uri}e"

  RewriteCond %{HTTP:Upgrade} websocket [NC]
  RewriteCond %{HTTP:Connection} upgrade [NC]
  RewriteRule /rsconnect/(.*) "ws://posit-connect-host:3939/$1" [P,L]

  RewriteRule ^/rsconnect$ /rsconnect/ [R]

  <Location /rsconnect/>
    ProxyPass http://posit-connect-host:3939/ connectiontimeout=5
    ProxyPassReverse /rsconnect/
    ProxyPassReverse /
  </Location>
</VirtualHost>
Tip

If you have configured ProxyAuth.LoginURL, the authentication condition <If "%{REQUEST_URI} of the example above is no longer needed.

Configuration examples with user profile and unique identity support

In these examples, username is considered part of the user profile. An additional header is used to communicate user identity. See Configuring Proxied Authentication.

nginx

This is an nginx configuration example with user profile and unique identity support.

map $http_upgrade $connection_upgrade {
  default upgrade;
  ""      close;
}

map $http_cookie $auth_uniqueid {
  default "";
  "~*proxyauth-as-id=(?<uniqueid>[^;]+)" "$uniqueid";
}

map $http_cookie $auth_username {
  default "";
  "~*verified-user=(?<username>[^;]+)" "$username";
}

map $http_cookie $auth_firstname {
  default "";
  "~*proxyauth-as-first=(?<first>[^;]+)" "$first";
}

map $http_cookie $auth_lastname {
  default "";
  "~*proxyauth-as-last=(?<last>[^;]+)" "$last";
}

map $http_cookie $auth_email {
  default "";
  "~*proxyauth-as-email=(?<email>[^;]+)" "$email";
}

map "$http_x_auth_token" $has_token {
    default "";
    "~.+" "token";
}

map "$http_authorization" $has_key {
    default "";
    "~Key .+" "key";
}

map "$auth_uniqueid:$has_token:$has_key" $requires_auth {
  default 0;
  "::" 1;
}

server {
  listen 80 default_server;

  location /rsconnect/ {

    # Redirect directly to authentication if the username is not
    # present. Needed if there is no login endpoint in the proxy.
    if ($requires_auth = 1) {
      return 307 $scheme://$host:$server_port/auth/login?url=$request_uri;
    }

    rewrite                    ^/rsconnect/(.*)$ /$1 break;
    proxy_pass                 http://posit-connect-host:3939;
    proxy_redirect             / /rsconnect/;
    proxy_pass_request_headers on;
    proxy_connect_timeout      5;
    proxy_http_version         1.1;
    proxy_buffering            off; # Required for XHR-streaming

    proxy_set_header           Upgrade $http_upgrade;
    proxy_set_header           Connection $connection_upgrade;
    proxy_set_header           X-RSC-Request $scheme://$host:$server_port$request_uri;
    proxy_set_header           X-Auth-Uniqueid $auth_uniqueid;
    proxy_set_header           X-Auth-Username $auth_username;
    proxy_set_header           X-Auth-Firstname $auth_firstname;
    proxy_set_header           X-Auth-Lastname $auth_lastname;
    proxy_set_header           X-Auth-Email $auth_email;
  }
}
Tip

If you have configured ProxyAuth.LoginURL, the authentication condition if ($requires_auth = 1) of the example above is no longer needed.

Apache HTTP Server

This is an Apache HTTP server configuration example with user profile and unique identity support.

RewriteEngine on

<VirtualHost *:80>
  SetEnvIf Cookie "verified-user=([^;]+)" AuthUniqueId=$1
  SetEnvIf Cookie "proxyauth-as-user=([^;]+)" AuthUsername=$1
  SetEnvIf Cookie "proxyauth-as-first=([^;]+)" AuthFirstName=$1
  SetEnvIf Cookie "proxyauth-as-last=([^;]+)" AuthLastName=$1
  SetEnvIf Cookie "proxyauth-as-email=([^;]+)" AuthEmail=$1

  # Redirect directly to authentication if the username is not
  # present. Needed if there is no login endpoint in the proxy.
  <If "%{REQUEST_URI} !~ m#^/auth# && -z env('AuthUniqueId') && -z %{HTTP:X-Auth-Token} && %{HTTP:Authorization} !~ /Key .+/">
    Redirect 307 "%{REQUEST_SCHEME}://%{HTTP_HOST}/auth/login?url=%{REQUEST_URI}"
  </If>

  <If "-n env('AuthUniqueId')">
    RequestHeader set X-Auth-Uniqueid "%{AuthUniqueId}e"
  </If>
  <Else>
    RequestHeader unset X-Auth-Uniqueid
  </Else>
  <If "-n env('AuthUsername')">
    RequestHeader set X-Auth-Username "%{AuthUsername}e"
  </If>
  <Else>
    RequestHeader unset X-Auth-Username
  </Else>
  <If "-n env('AuthFirstName')">
    RequestHeader set X-Auth-Firstname "%{AuthFirstName}e"
  </If>
  <Else>
    RequestHeader unset X-Auth-Firstname
  </Else>
  <If "-n env('AuthLastName')">
    RequestHeader set X-Auth-Lastname "%{AuthLastName}e"
  </If>
  <Else>
    RequestHeader unset X-Auth-Lastname
  </Else>
  <If "-n env('AuthEmail')">
    RequestHeader set X-Auth-Email "%{AuthEmail}e"
  </If>
  <Else>
    RequestHeader unset X-Auth-Email
  </Else>

  # store variable values with dummy rewrite rules
  RewriteRule . - [E=req_scheme:%{REQUEST_SCHEME}]
  RewriteRule . - [E=http_host:%{HTTP_HOST}]
  RewriteRule . - [E=req_uri:%{REQUEST_URI}]
  # set header with variables
  RequestHeader set X-RSC-Request "%{req_scheme}e://%{http_host}e%{req_uri}e"

  RewriteCond %{HTTP:Upgrade} websocket [NC]
  RewriteCond %{HTTP:Connection} upgrade [NC]
  RewriteRule /rsconnect/(.*) "ws://posit-connect-host:3939/$1" [P,L]

  RewriteRule ^/rsconnect$ /rsconnect/ [R]

  <Location /rsconnect/>
    ProxyPass http://posit-connect-host:3939/ connectiontimeout=5
    ProxyPassReverse /rsconnect/
    ProxyPassReverse /
  </Location>
</VirtualHost>
Tip

If you have configured ProxyAuth.LoginURL, the authentication condition <If "%{REQUEST_URI} of the example above is no longer needed.