an SSO and OAuth / OIDC login solution for Nginx using the auth_request module

Overview

Vouch Proxy

GitHub stars Go Report Card MIT license Docker pulls GitHub version

An SSO solution for Nginx using the auth_request module. Vouch Proxy can protect all of your websites at once.

Vouch Proxy supports many OAuth and OIDC login providers and can enforce authentication to...

Please do let us know when you have deployed Vouch Proxy with your preffered IdP or library so we can update the list.

If Vouch is running on the same host as the Nginx reverse proxy the response time from the /validate endpoint to Nginx should be less than 1ms


Table of Contents


What Vouch Proxy Does...

Vouch Proxy (VP) forces visitors to login and authenticate with an IdP (such as one of the services listed above) before allowing them access to a website.

Vouch Proxy protects websites

VP can also be used as a Single Sign On (SSO) solution to protect all web applications in the same domain.

Vouch Proxy is a Single Sign On solution

After a visitor logs in Vouch Proxy allows access to the protected websites for several hours. Every request is checked by VP to ensure that it is valid.

VP can send the visitor's email, name and other information which the IdP provides (including access tokens) to the web application as HTTP headers. VP can be used to replace application user management entirely.

Installation and Configuration

Vouch Proxy relies on the ability to share a cookie between the Vouch Proxy server and the application it's protecting. Typically this will be done by running Vouch on a subdomain such as vouch.yourdomain.com with apps running at app1.yourdomain.com and app2.yourdomain.com. The protected domain is .yourdomain.com and the Vouch Proxy cookie must be set in this domain by setting vouch.domains to include yourdomain.com or sometimes by setting vouch.cookie.domain to yourdomain.com.

  • cp ./config/config.yml_example_$OAUTH_PROVIDER ./config/config.yml
  • create OAuth credentials for Vouch Proxy at google or github, etc
    • be sure to direct the callback URL to the Vouch Proxy /auth endpoint
  • configure Nginx...

The following Nginx config assumes..

  • Nginx, vouch.yourdomain.com and protectedapp.yourdomain.com are running on the same server
  • both domains are served as https and have valid certs (if not, change to listen 80 and set vouch.cookie.secure to false)
server {
    listen 443 ssl http2;
    server_name protectedapp.yourdomain.com;
    root /var/www/html/;

    ssl_certificate /etc/letsencrypt/live/protectedapp.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/protectedapp.yourdomain.com/privkey.pem;

    # send all requests to the `/validate` endpoint for authorization
    auth_request /validate;

    location = /validate {
      # forward the /validate request to Vouch Proxy
      proxy_pass http://127.0.0.1:9090/validate;
      # be sure to pass the original host header
      proxy_set_header Host $http_host;

      # Vouch Proxy only acts on the request headers
      proxy_pass_request_body off;
      proxy_set_header Content-Length "";

      # optionally add X-Vouch-User as returned by Vouch Proxy along with the request
      auth_request_set $auth_resp_x_vouch_user $upstream_http_x_vouch_user;

      # optionally add X-Vouch-IdP-Claims-* custom claims you are tracking
      #    auth_request_set $auth_resp_x_vouch_idp_claims_groups $upstream_http_x_vouch_idp_claims_groups;
      #    auth_request_set $auth_resp_x_vouch_idp_claims_given_name $upstream_http_x_vouch_idp_claims_given_name;
      # optinally add X-Vouch-IdP-AccessToken or X-Vouch-IdP-IdToken
      #    auth_request_set $auth_resp_x_vouch_idp_accesstoken $upstream_http_x_vouch_idp_accesstoken;
      #    auth_request_set $auth_resp_x_vouch_idp_idtoken $upstream_http_x_vouch_idp_idtoken;

      # these return values are used by the @error401 call
      auth_request_set $auth_resp_jwt $upstream_http_x_vouch_jwt;
      auth_request_set $auth_resp_err $upstream_http_x_vouch_err;
      auth_request_set $auth_resp_failcount $upstream_http_x_vouch_failcount;

      # Vouch Proxy can run behind the same Nginx reverse proxy
      # may need to comply to "upstream" server naming
      # proxy_pass http://vouch.yourdomain.com/validate;
      # proxy_set_header Host $http_host;
    }

    # if validate returns `401 not authorized` then forward the request to the error401block
    error_page 401 = @error401;

    location @error401 {
        # redirect to Vouch Proxy for login
        return 302 https://vouch.yourdomain.com/login?url=$scheme://$http_host$request_uri&vouch-failcount=$auth_resp_failcount&X-Vouch-Token=$auth_resp_jwt&error=$auth_resp_err;
        # you usually *want* to redirect to Vouch running behind the same Nginx config proteced by https
        # but to get started you can just forward the end user to the port that vouch is running on
        # return 302 http://vouch.yourdomain.com:9090/login?url=$scheme://$http_host$request_uri&vouch-failcount=$auth_resp_failcount&X-Vouch-Token=$auth_resp_jwt&error=$auth_resp_err;
    }

    location / {
      # forward authorized requests to your service protectedapp.yourdomain.com
      proxy_pass http://127.0.0.1:8080;
      # you may need to set these variables in this block as per https://github.com/vouch/vouch-proxy/issues/26#issuecomment-425215810
      #    auth_request_set $auth_resp_x_vouch_user $upstream_http_x_vouch_user
      #    auth_request_set $auth_resp_x_vouch_idp_claims_groups $upstream_http_x_vouch_idp_claims_groups;
      #    auth_request_set $auth_resp_x_vouch_idp_claims_given_name $upstream_http_x_vouch_idp_claims_given_name;

      # set user header (usually an email)
      proxy_set_header X-Vouch-User $auth_resp_x_vouch_user;
      # optionally pass any custom claims you are tracking
      #     proxy_set_header X-Vouch-IdP-Claims-Groups $auth_resp_x_vouch_idp_claims_groups;
      #     proxy_set_header X-Vouch-IdP-Claims-Given_Name $auth_resp_x_vouch_idp_claims_given_name;
      # optionally pass the accesstoken or idtoken
      #     proxy_set_header X-Vouch-IdP-AccessToken $auth_resp_x_vouch_idp_accesstoken;
      #     proxy_set_header X-Vouch-IdP-IdToken $auth_resp_x_vouch_idp_idtoken;
    }
}

If Vouch is configured behind the same nginx reverseproxy (perhaps so you can configure ssl) be sure to pass the Host header properly, otherwise the JWT cookie cannot be set into the domain

server {
    listen 443 ssl http2;
    server_name vouch.yourdomain.com;
    ssl_certificate /etc/letsencrypt/live/vouch.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/vouch.yourdomain.com/privkey.pem;

    location / {
      proxy_pass http://127.0.0.1:9090;
      # be sure to pass the original host header
      proxy_set_header Host $http_host;
    }
}

Additional Nginx configurations can be found in the examples directory.

Configuring Vouch Proxy using Environmental Variables

Here's a minimal setup using Google OAuth...

VOUCH_DOMAINS=yourdomain.com \
  OAUTH_PROVIDER=google \
  OAUTH_CLIENT_ID=1234 \
  OAUTH_CLIENT_SECRET=secretsecret \
  OAUTH_CALLBACK_URL=https://vouch.yourdomain.com/auth \
  ./vouch-proxy

Environmental variable names are documented in config/config.yml_example

All lists with multiple values must be comma separated: VOUCH_DOMAINS="yourdomain.com,yourotherdomain.com"

The variable VOUCH_CONFIG can be used to set an alternate location for the configuration file. VOUCH_ROOT can be used to set an alternate root directory for Vouch Proxy to look for support files.

More advanced configurations

All Vouch Proxy configuration items are documented in config/config.yml_example

Please do help us to expand this list.

Scopes and Claims

With Vouch Proxy you can request various scopes (standard and custom) to obtain more information about the user or gain access to the provider's APIs. Internally, Vouch Proxy launches a requests to user_info_url after successful authentication. From the provider's response the required claims are extracted and stored in the vouch cookie.

⚠️ Additional claims and tokens will be added to the VP cookie and can make it large

The VP cookie may get split up into several cookies, but if you need it, you need it. Large cookies and headers require Nginx to be configured with larger buffers. See large_client_header_buffers and proxy_buffer_size for more information.

Setup scopes and claims in Vouch Proxy with Nginx

  1. Configure Vouch Proxy for Nginx and your IdP as normal (See: Installation and Configuration)

  2. Set the necessary scopes in the oauth section of the vouch-proxy config.yml (example config)

    1. set idtoken: X-Vouch-IdP-IdToken in the headers section of vouch-proxy's config.yml
    2. log in and call the /validate endpoint in a modern browser
    3. check the response header for a X-Vouch-IdP-IdToken header
    4. copy the value of the header into the debugger at https://jwt.io/ and ensure that the necessary claims are part of the jwt
    5. if they are not, you need to adjust the scopes in the oauth section of your config.yml or reconfigure your oauth provider
  3. Set the necessary claims in the header section of the vouch-proxy config.yml

    1. log in and call the /validate endpoint in a modern browser
    2. check the response headers for headers of the form X-Vouch-Idp-Claims-<ClaimName>
    3. If they are not there clear your cookies and cached browser data
    4. 🐞 If they are still not there but exist in the jwt (esp. custom claims) there might be a bug
    5. remove the idtoken: X-Vouch-IdP-IdToken from the headers section of vouch-proxy's config.yml if you don't need it
  4. Use auth_request_set after auth_request inside the protected location in the nginx server.conf

  5. Consume the claim (example nginx config)

Running from Docker

docker run -d \
    -p 9090:9090 \
    --name vouch-proxy \
    -v ${PWD}/config:/config \
    voucher/vouch-proxy

or

docker run -d \
    -p 9090:9090 \
    --name vouch-proxy \
    -e VOUCH_DOMAINS=yourdomain.com \
    -e OAUTH_PROVIDER=google \
    -e OAUTH_CLIENT_ID=1234 \
    -e OAUTH_CLIENT_SECRET=secretsecret \
    -e OAUTH_CALLBACK_URL=https://vouch.yourdomain.com/auth \
    voucher/vouch-proxy

Automated container builds for each Vouch Proxy release are available from Docker Hub. Each release produces..

  • voucher/vouch-proxy:latest
  • voucher/vouch-proxy:x.y.z
  • voucher/vouch-proxy:alpine
  • voucher/vouch-proxy:alpine-x.y.z
  • voucher/vouch-proxy:latest-arm

Kubernetes Nginx Ingress

If you are using kubernetes with nginx-ingress, you can configure your ingress with the following annotations (note quoting the auth-signin annotation):

    nginx.ingress.kubernetes.io/auth-signin: "https://vouch.yourdomain.com/login?url=$scheme://$http_host$request_uri&vouch-failcount=$auth_resp_failcount&X-Vouch-Token=$auth_resp_jwt&error=$auth_resp_err"
    nginx.ingress.kubernetes.io/auth-url: https://vouch.yourdomain.com/validate
    nginx.ingress.kubernetes.io/auth-response-headers: X-Vouch-User
    nginx.ingress.kubernetes.io/auth-snippet: |
      # these return values are used by the @error401 call
      auth_request_set $auth_resp_jwt $upstream_http_x_vouch_jwt;
      auth_request_set $auth_resp_err $upstream_http_x_vouch_err;
      auth_request_set $auth_resp_failcount $upstream_http_x_vouch_failcount;

Helm Charts are maintained by halkeye and are available at https://github.com/halkeye-helm-charts/vouch / https://halkeye.github.io/helm-charts/

Compiling from source and running the binary

  ./do.sh goget
  ./do.sh build
  ./vouch-proxy

/login and /logout endpoint redirection

As of v0.11.0 additional checks are in place to reduce the attack surface of url redirection.

/login?url=POST_LOGIN_URL

The passed URL...

  • must start with either http or https
  • must have a domain overlap with either a domain in the vouch.domains list or the vouch.cookie.domain (if either of those are configured)
  • cannot have a parameter which includes a URL to prevent URL chaining attacks

/logout?url=NEXT_URL

The Vouch Proxy /logout endpoint accepts a url parameter in the query string which can be used to 302 redirect a user to your orignal OAuth provider/IDP/OIDC provider's revocation_endpoint

    https://vouch.oursites.com/logout?url=https://oauth2.googleapis.com/revoke

this url must be present in the configuration file on the list vouch.post_logout_redirect_uris

# in order to prevent redirection attacks all redirected URLs to /logout must be specified
# the URL must still be passed to Vouch Proxy as https://vouch.yourdomain.com/logout?url=${ONE OF THE URLS BELOW}
post_logout_redirect_uris:
  # your apps login page
  - http://.yourdomain.com/login
  # your IdPs logout enpoint
  # from https://accounts.google.com/.well-known/openid-configuration
  - https://oauth2.googleapis.com/revoke
  # you may be daisy chaining to your IdP
  - https://myorg.okta.com/oauth2/123serverid/v1/logout?post_logout_redirect_uri=http://myapp.yourdomain.com/login

Note that your IdP will likely carry their own, separate post_logout_redirect_uri list.

logout resources..

Troubleshooting, Support and Feature Requests (Read this before submitting an issue at GitHub)

Getting the stars to align between Nginx, Vouch Proxy and your IdP can be tricky. We want to help you get up and running as quickly as possible. The most common problem is..

I'm getting an infinite redirect loop which returns me to my IdP (Google/Okta/GitHub/...)

Double check that you are running Vouch Proxy and your apps on a common domain that can share cookies. For example, vouch.yourdomain.com and app.yourdomain.com can share cookies on the .yourdomain.com domain. (It will not work if you are trying to use vouch.yourdomain.org and app.yourdomain.net.)

You may need to explicitly define the domain that the cookie should be set on. You can do this in the config file by setting the option:

vouch:
  cookie:
    # force the domain of the cookie to set
    domain: yourdomain.com

If you continue to have trouble, try the following:

  • turn on vouch.testing: true. This will slow down the loop.

  • set vouch.logLevel: debug.

  • the Host: header in the http request, the oauth.callback_url and the configured vouch.domains must all align so that the cookie that carries the JWT can be placed properly into the browser and then returned on each request

  • it helps to think like a cookie.

    • a cookie is set into a domain. If you have siteA.yourdomain.com and siteB.yourdomain.com protected by Vouch Proxy, you want the Vouch Proxy cookie to be set into .yourdomain.com
    • if you authenticate to vouch.yourdomain.com the cookie will not be able to be seen by dev.anythingelse.com
    • unless you are using https, you should set vouch.cookie.secure: false
    • cookies are available to all ports of a domain
  • please see the issues which have been closed that mention redirect

Okay, I looked at the issues and have tried some things with my configs but it's still not working

Please submit a new issue in the following fashion..

TLDR:

  • set vouch.testing: true
  • set vouch.logLevel: debug
  • conduct a full round trip of ./vouch-proxy capturing the output..
    • VP startup
    • /validate
    • /login - even if the error is here
    • /auth
    • /validate - capture everything
  • put all your logs and config in a gist.
  • ./do.sh bug_report is your friend

But read this anyways because we'll ask you to read it if you don't follow these instruction. :)

  • turn on vouch.testing: true and set vouch.logLevel: debug.
  • use a gist or another paste service such as hasteb.in. DO NOT PUT YOUR LOGS AND CONFIG INTO THE GITHUB ISSUE. Using a paste service is important as it will maintain spacing and will provide line numbers and formatting. We are hunting for needles in haystacks with setups with several moving parts, these features help considerably. Paste services save your time and our time and help us to help you quickly. You're more likely to get good support from us in a timely manner by following this advice.
  • run ./do.sh bug_report secretdomain.com secretpass [anothersecret..] which will create a redacted version of your config and logs removing each of those strings
    • and follow the instructions at the end to redact your Nginx config
  • all of those go into a gist
  • then open a new issue in this repository
  • or visit our IRC channel #vouch on freenode

A bug report can be generated from a docker environment using the voucher/vouch-proxy:alpine image...

docker run --name vouch_proxy -v $PWD/config:/config -v $PWD/certs:/certs -it --rm --entrypoint /do.sh voucher/vouch-proxy:alpine bug_report yourdomain.com anotherdomain.com someothersecret

submitting a Pull Request for a new feature

I really love Vouch Proxy! I wish it did XXXX...

Please make a proposal before you spend your time and our time integrating a new feature.

Code contributions should..

  • include unit tests and in some cases end-to-end tests
  • be formatted with go fmt, checked with go vet and other common go tools
  • not break existing setups without a clear reason (usually security related)
  • and generally be discussed beforehand in a GitHub issue

For larger contributions or code related to a platform that we don't currently support we will ask you to commit to supporting the feature for an agreed upon period. Invariably someone will pop up here with a question and we want to be able to support these requests.

Advanced Authorization Using OpenResty

OpenResty® is a full-fledged web platform that integrates the standard Nginx core, LuaJIT, many carefully written Lua libraries, lots of high quality 3rd-party Nginx modules, and most of their external dependencies.

You can replace nginx with OpenResty fairly easily.

With OpenResty and Lua it is possible to provide customized and advanced authorization on any header or claims vouch passes down.

OpenResty and configs for a variety of scenarios are available in the examples directory.

The flow of login and authentication using Google Oauth

  • Bob visits https://private.oursites.com

  • the Nginx reverse proxy...

    • recieves the request for private.oursites.com from Bob
    • uses the auth_request module configured for the /validate path
    • /validate is configured to proxy_pass requests to the authentication service at https://vouch.oursites.com/validate
      • if /validate returns...
        • 200 OK then SUCCESS allow Bob through
        • 401 NotAuthorized then
          • respond to Bob with a 302 redirect to https://vouch.oursites.com/login?url=https://private.oursites.com
  • Vouch Proxy https://vouch.oursites.com/validate

    • recieves the request for private.oursites.com from Bob via Nginx proxy_pass
    • looks for a cookie named "oursitesSSO" that contains a JWT
    • if the cookie is found, and the JWT is valid
      • returns 200 OK to Nginx, which will allow access (bob notices nothing)
    • if the cookie is NOT found, or the JWT is NOT valid
      • return 401 NotAuthorized to Nginx (which forwards the request on to login)
  • Bob is first forwarded briefly to https://vouch.oursites.com/login?url=https://private.oursites.com

    • clears out the cookie named "oursitesSSO" if it exists
    • generates a nonce and stores it in session variable $STATE
    • stores the url https://private.oursites.com from the query string in session variable $requestedURL
    • respond to Bob with a 302 redirect to Google's OAuth Login form, including the $STATE nonce
  • Bob logs into his Google account using Oauth

    • after successful login
    • Google responds to Bob with a 302 redirect to https://vouch.oursites.com/auth?state=$STATE
  • Bob is forwarded to https://vouch.oursites.com/auth?state=$STATE

    • if the $STATE nonce from the url matches the session variable "state"
    • make a "third leg" request of Google (server to server) to exchange the OAuth code for Bob's user info including email address [email protected]
    • if the email address matches the domain oursites.com (it does)
      • issue bob a JWT in the form of a cookie named "oursitesSSO"
      • retrieve the session variable $requestedURL and 302 redirect bob back to https://private.oursites.com

Note that outside of some innocuos redirection, Bob only ever sees https://private.oursites.com and the Google Login screen in his browser. While Vouch does interact with Bob's browser several times, it is just to set cookies, and if the 302 redirects work properly Bob will log in quickly.

Once the JWT is set, Bob will be authorized for all other sites which are configured to use https://vouch.oursites.com/validate from the auth_request Nginx module.

The next time Bob is forwarded to google for login, since he has already authorized the Vouch Proxy OAuth app, Google immediately forwards him back and sets the cookie and sends him on his merry way. In some browsers such as Chrome, Bob may not even notice that he logged in using Vouch Proxy.

Issues
  • Azure AD userinfo ID claim

    Azure AD userinfo ID claim

    started getting this message today.

    json: cannot unmarshal string into Go struct field User.id of type int

    tracked it down to the fact that Azure userinfo endpoint started returning an id field that looks like \"id\":\"alphanumeric-alphanumeric-alphanumeric-alphanumeric-alphanumeric\" rather than what vouch is expecting (int)

    https://github.com/vouch/vouch-proxy/blob/ded2e2580345a0edd27aed5f2043e692e947845c/pkg/structs/structs.go#L23

    Wonder how it was decided id should be an int? Don't see it specified under https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims or https://connect2id.com/products/server/docs/api/userinfo#claims

    This flow was working fine yesterday, and just broke this morning. Vouch configuration looks like

    vouch:
      domains:
      - my.webpage.com
    
      jwt:
        issuer: Vouch
        maxAge: 120
        compress: true
    
      cookie:
        name: VouchCookie
        secure: true
        httpOnly: true
        maxAge: 480
    
      session:
        name: VouchSession
        
      headers:
        jwt: X-Vouch-Token
        querystring: access_token
        redirect: X-Vouch-Requested-URI
    
    oauth:
      # Generic OpenID Connect
      provider: oidc
      client_id: "client_id_string"
      client_secret: "client_secret"
      auth_url: https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/authorize
      token_url: https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token
      user_info_url: https://graph.microsoft.com/oidc/userinfo
      scopes:
        - openid
        - email
        - profile
      callback_urls:
        - https://my.webpage.com
    
    bug 
    opened by hwshadow 42
  • too many redirects using duckdns.org domains

    too many redirects using duckdns.org domains

    Hi,

    I also have the most popular issue here.

    Too many redirects and no jwt found in request.

    In my case the difference is that I don't have a domain, rather I'm using duckdns.org service and I don't know if it will work at all so...

    I've created 2 subdomains mydomain.duckdns.org and login-mydomain.duckdns.org

    Here's my vouch config:

     
      testing: true
    
      cookie:
       domain: duckdns.org
       name: VouchCookie
       secure: true
       httpOnly: true
    
      allowAllUsers: true
    
    oauth:
    
      provider: oidc
      client_id: XXXXXXXXXXX
      client_secret: XXXXXXXXXXX
      auth_url: https://dev-254313.okta.com/oauth2/default/v1/authorize
      token_url: https://dev-254313.okta.com/oauth2/default/v1/token
      user_info_url: https://dev-254313.okta.com/oauth2/default/v1/userinfo
      scopes:
        - openid
        - email
        - profile
      callback_url: https://login-++++++++++.+++++++.+++/auth
    

    And my nginx config:

    server {
        listen 443 ssl; # managed by Certbot
        server_name login-mydomain.duckdns.org;
    
        # Proxy to your Vouch instance
        location / {
            proxy_pass        http://127.0.0.1:9090;
            proxy_set_header Host $http_host;
       }
    
        ssl_certificate /etc/letsencrypt/live/mydomain.duckdns.org/fullchain.pem; # managed by Certbot
        ssl_certificate_key /etc/letsencrypt/live/mydomain.duckdns.org/privkey.pem; # managed by Certbot
    }
    
    server {
        server_name mydomain.duckdns.org;
    
        listen [::]:443 ssl ipv6only=on; # managed by Certbot
        listen 443 ssl; # managed by Certbot
        include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
    
        # Any request to this server will first be sent to this URL
        auth_request /validate;
    
        location = /validate {
          # This address is where Vouch will be listening on
          proxy_pass http://127.0.0.1:9090/validate;
          proxy_set_header Host $http_host;
          proxy_pass_request_body off; # no need to send the POST body
    
          proxy_set_header Content-Length "";
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header X-Forwarded-Proto $scheme;
    
          # these return values are passed to the @error401 call
          auth_request_set $auth_resp_jwt $upstream_http_x_vouch_jwt;
          auth_request_set $auth_resp_err $upstream_http_x_vouch_err;
          auth_request_set $auth_resp_failcount $upstream_http_x_vouch_failcount;
        }
    
        error_page 401 = @error401;
    	#If the user is not logged in, redirect them to Vouch's login URL
        location @error401 {
            return 302 https://login-mydomain.duckdns.org/login?url=$scheme://$http_host$request_uri&vouch-failcount=$auth_resp_failcount&X-Vouch-Token=$auth_resp_jwt&error=$auth_resp_err;
        }
    
        location / {
            proxy_pass http://localhost:1880/;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        }
    
    
        ssl_certificate /etc/letsencrypt/live/mydomain.duckdns.org/fullchain.pem; # managed by Certbot
        ssl_certificate_key /etc/letsencrypt/live/mydomain.duckdns.org/privkey.pem; # managed by Certbot
    }
    
    server {
        if ($host = mydomain.duckdns.org) {
            return 301 https://$host$request_uri;
        } # managed by Certbot
    
    
        listen 80 default_server;
        listen [::]:80 default_server;
        server_name mydomain.duckdns.org;
        return 404; # managed by Certbot
    }
    

    And finally the log:

    {"level":"info","ts":1564811271.6428761,"msg":"jwt.secret read from /home/pi/vouch-proxy/config/secret"}
    {"level":"warn","ts":1564811271.6439126,"msg":"generating random session.key"}
    {"level":"info","ts":1564811271.645211,"msg":"configuring oidc OAuth with Endpoint https://dev-254313.okta.com/oauth2/default/v1/authorize"}
    {"level":"info","ts":1564811271.6522284,"msg":"starting Vouch","version":"98e009a","buildtime":"2019-07-29T19:44:07Z","buildhost":"nginxpi","branch":"master","semver":"v0.6.4","listen":"0.0.0.0:9090","oauth.provider":"oidc"}
    
    
    
    
    
    
    {"level":"error","ts":1564811280.29344,"msg":"no jwt found in request"}
    {"level":"warn","ts":1564811280.294039,"msg":"domain mydomain.duckdns.org not found in any domains []"}
    {"level":"info","ts":1564811280.2944045,"msg":"|401|  918.908µs /validate","statusCode":401,"request":1,"latency":0.000918908,"avgLatency":0.000918908,"ipPort":"127.0.0.1:51596","method":"GET","host":"mydomain.duckdns.org","path":"/validate","referer":""}
    {"level":"warn","ts":1564811280.6684415,"msg":"domain login-mydomain.duckdns.org not found in any domains []"}
    {"level":"info","ts":1564811280.6712873,"msg":"|302| 3.069538ms /login","statusCode":302,"request":2,"latency":0.003069538,"avgLatency":0.001994223,"ipPort":"127.0.0.1:51598","method":"GET","host":"login-mydomain.duckdns.org","path":"/login","referer":""}
    {"level":"info","ts":1564811292.743179,"msg":"OpenID userinfo body: %!(EXTRA string={\"sub\":\"00u10sz2uca2AL8Do357\",\"name\":\"xxxx xxxxxxx\",\"locale\":\"en-US\",\"email\":\"[email protected]\",\"preferred_username\":\"[email protected]\",\"given_name\":\"xxxx\",\"family_name\":\"xxxxxxx\",\"zoneinfo\":\"America/Los_Angeles\",\"updated_at\":1564463612,\"email_verified\":true})"}
    {"level":"warn","ts":1564811292.7596512,"msg":"domain login-mydomain.duckdns.org not found in any domains []"}
    {"level":"info","ts":1564811292.7618918,"msg":"|302| 2.568484708s /auth","statusCode":302,"request":3,"latency":2.568484708,"avgLatency":0.857491051,"ipPort":"127.0.0.1:51600","method":"GET","host":"login-mydomain.duckdns.org","path":"/auth","referer":""}
    {"level":"error","ts":1564811292.7774441,"msg":"no jwt found in request"}
    {"level":"warn","ts":1564811292.7780569,"msg":"domain mydomain.duckdns.org not found in any domains []"}
    {"level":"info","ts":1564811292.7784107,"msg":"|401|  943.908µs /validate","statusCode":401,"request":4,"latency":0.000943908,"avgLatency":0.643354266,"ipPort":"127.0.0.1:51604","method":"GET","host":"mydomain.duckdns.org","path":"/validate","referer":""}
    {"level":"warn","ts":1564811292.7923298,"msg":"domain login-mydomain.duckdns.org not found in any domains []"}
    {"level":"info","ts":1564811292.7970688,"msg":"|302| 4.813604ms /login","statusCode":302,"request":5,"latency":0.004813604,"avgLatency":0.515646134,"ipPort":"127.0.0.1:51606","method":"GET","host":"login-mydomain.duckdns.org","path":"/login","referer":""}
    {"level":"info","ts":1564811293.9997418,"msg":"OpenID userinfo body: %!(EXTRA string={\"sub\":\"00u10sz2uca2AL8Do357\",\"name\":\"xxxx xxxxxxx\",\"locale\":\"en-US\",\"email\":\"[email protected]\",\"preferred_username\":\"[email protected]\",\"given_name\":\"xxxx\",\"family_name\":\"xxxxxxx\",\"zoneinfo\":\"America/Los_Angeles\",\"updated_at\":1564463612,\"email_verified\":true})"}
    {"level":"warn","ts":1564811294.0172899,"msg":"domain login-mydomain.duckdns.org not found in any domains []"}
    {"level":"info","ts":1564811294.020052,"msg":"|302| 921.930437ms /auth","statusCode":302,"request":6,"latency":0.921930437,"avgLatency":0.583360184,"ipPort":"127.0.0.1:51608","method":"GET","host":"login-mydomain.duckdns.org","path":"/auth","referer":""}
    {"level":"error","ts":1564811294.0317314,"msg":"no jwt found in request"}
    {"level":"warn","ts":1564811294.0321395,"msg":"domain mydomain.duckdns.org not found in any domains []"}
    {"level":"info","ts":1564811294.0324323,"msg":"|401|   679.95µs /validate","statusCode":401,"request":7,"latency":0.00067995,"avgLatency":0.500120151,"ipPort":"127.0.0.1:51610","method":"GET","host":"mydomain.duckdns.org","path":"/validate","referer":""}
    {"level":"warn","ts":1564811294.0429945,"msg":"domain login-mydomain.duckdns.org not found in any domains []"}
    {"level":"info","ts":1564811294.0461886,"msg":"|302| 3.255632ms /login","statusCode":302,"request":8,"latency":0.003255632,"avgLatency":0.438012087,"ipPort":"127.0.0.1:51612","method":"GET","host":"login-mydomain.duckdns.org","path":"/login","referer":""}
    {"level":"info","ts":1564811295.2238116,"msg":"OpenID userinfo body: %!(EXTRA string={\"sub\":\"00u10sz2uca2AL8Do357\",\"name\":\"xxxx xxxxxxx\",\"locale\":\"en-US\",\"email\":\"[email protected]\",\"preferred_username\":\"[email protected]\",\"given_name\":\"xxxx\",\"family_name\":\"xxxxxxx\",\"zoneinfo\":\"America/Los_Angeles\",\"updated_at\":1564463612,\"email_verified\":true})"}
    {"level":"warn","ts":1564811295.239589,"msg":"domain login-mydomain.duckdns.org not found in any domains []"}
    {"level":"info","ts":1564811295.2417097,"msg":"|302| 858.309363ms /auth","statusCode":302,"request":9,"latency":0.858309363,"avgLatency":0.484711784,"ipPort":"127.0.0.1:51614","method":"GET","host":"login-mydomain.duckdns.org","path":"/auth","referer":""}
    {"level":"error","ts":1564811295.2560842,"msg":"no jwt found in request"}
    {"level":"warn","ts":1564811295.2566383,"msg":"domain mydomain.duckdns.org not found in any domains []"}
    {"level":"info","ts":1564811295.2570825,"msg":"|401|  903.543µs /validate","statusCode":401,"request":10,"latency":0.000903543,"avgLatency":0.43633096,"ipPort":"127.0.0.1:51616","method":"GET","host":"mydomain.duckdns.org","path":"/validate","referer":""}
    {"level":"warn","ts":1564811295.2691314,"msg":"domain login-mydomain.duckdns.org not found in any domains []"}
    {"level":"info","ts":1564811295.2720904,"msg":"|302| 2.991517ms /login","statusCode":302,"request":11,"latency":0.002991517,"avgLatency":0.396936466,"ipPort":"127.0.0.1:51618","method":"GET","host":"login-mydomain.duckdns.org","path":"/login","referer":""}
    {"level":"info","ts":1564811296.3716736,"msg":"OpenID userinfo body: %!(EXTRA string={\"sub\":\"00u10sz2uca2AL8Do357\",\"name\":\"xxxx xxxxxxx\",\"locale\":\"en-US\",\"email\":\"[email protected]\",\"preferred_username\":\"[email protected]\",\"given_name\":\"xxxx\",\"family_name\":\"xxxxxxx\",\"zoneinfo\":\"America/Los_Angeles\",\"updated_at\":1564463612,\"email_verified\":true})"}
    {"level":"warn","ts":1564811296.3934019,"msg":"domain login-mydomain.duckdns.org not found in any domains []"}
    {"level":"info","ts":1564811296.396406,"msg":"|302| 820.775427ms /auth","statusCode":302,"request":12,"latency":0.820775427,"avgLatency":0.432256379,"ipPort":"127.0.0.1:51620","method":"GET","host":"login-mydomain.duckdns.org","path":"/auth","referer":""}
    {"level":"error","ts":1564811296.434284,"msg":"no jwt found in request"}
    {"level":"warn","ts":1564811296.43474,"msg":"domain mydomain.duckdns.org not found in any domains []"}
    {"level":"info","ts":1564811296.4350607,"msg":"|401|  746.929µs /validate","statusCode":401,"request":13,"latency":0.000746929,"avgLatency":0.399063345,"ipPort":"127.0.0.1:51622","method":"GET","host":"mydomain.duckdns.org","path":"/validate","referer":""}
    {"level":"warn","ts":1564811296.4487345,"msg":"domain login-mydomain.duckdns.org not found in any domains []"}
    {"level":"info","ts":1564811296.451844,"msg":"|302| 3.182194ms /login","statusCode":302,"request":14,"latency":0.003182194,"avgLatency":0.37078612,"ipPort":"127.0.0.1:51624","method":"GET","host":"login-mydomain.duckdns.org","path":"/login","referer":""}
    {"level":"info","ts":1564811297.3613815,"msg":"OpenID userinfo body: %!(EXTRA string={\"sub\":\"00u10sz2uca2AL8Do357\",\"name\":\"xxxx xxxxxxx\",\"locale\":\"en-US\",\"email\":\"[email protected]\",\"preferred_username\":\"[email protected]\",\"given_name\":\"xxxx\",\"family_name\":\"xxxxxxx\",\"zoneinfo\":\"America/Los_Angeles\",\"updated_at\":1564463612,\"email_verified\":true})"}
    {"level":"warn","ts":1564811297.3736796,"msg":"domain login-mydomain.duckdns.org not found in any domains []"}
    {"level":"info","ts":1564811297.3754253,"msg":"|302| 621.531881ms /auth","statusCode":302,"request":15,"latency":0.621531881,"avgLatency":0.387502504,"ipPort":"127.0.0.1:51626","method":"GET","host":"login-mydomain.duckdns.org","path":"/auth","referer":""}
    
    question 
    opened by scotie 42
  • redirection from `/auth` to `/auth/$STATE` fails when VP is hosted at a path such as `/vouch` (redirects to `/auth/$STATE` instead of `/vouch/auth/$STATE`)

    redirection from `/auth` to `/auth/$STATE` fails when VP is hosted at a path such as `/vouch` (redirects to `/auth/$STATE` instead of `/vouch/auth/$STATE`)

    Use a Paste Service

    Link to logs with vouch.testing set to true

    Describe the problem

    Vouch has been configured to work with Okta and nginx. With all version up to 0.19.2 it works well. When we update to 0.20.0 or newer versions, the process works until the last redirection after being correctly logged. The reason is that the redirect URL is wrong, it forgets a part.

    Instead of redirecting to https://app-dev.our-domain.something/vouch-webapp-dev/auth it sends to https://app-dev.our-domain.something/auth and it finishes with a 404 error.

    Last lines of the kindof Vouch report generated in testing mode through the browser (after the Okta login screen): image

    Expected behavior

    We expect that version 0.20.0 or newer to work like version 0.19.2 or older, in particular to not get

    Additional context

    Vouch config updated (with secure: true)

    We run Vouch on docker-swarm: image: voucher/vouch-proxy:0.19.2

    Tests has been run on Chrome 0.89 and Ubuntu 20.10

    bug 
    opened by pommedeterresautee 36
  • OAuth Provider logout?

    OAuth Provider logout?

    Can the OAuth provider logout be implemented? For Okta, this would require the passing an id_token.. which could be obtained using the access_token obtained obtained here:

    providerToken, err := cfg.OAuthClient.Exchange(oauth2.NoContext, r.URL.Query().Get("code"))

    enhancement 
    opened by cmollis 34
  • Difference with pusher oauth proxy and how to validate a request directly from an application

    Difference with pusher oauth proxy and how to validate a request directly from an application

    Hi,

    We are experimenting with vouch to secure some of our internal services and are wondering the reasons behind your approach to build this library. After some searching we also found https://github.com/pusher/oauth2_proxy which is quite similar but seems to be more mature. Could you explain more the rationale around vouch proxy and maybe the differences with other solutions. We are just curious :)

    question 
    opened by butsjoh 29
  • ADFS error: MSIS9604

    ADFS error: MSIS9604

    Config:

    vouch:
      logLevel: debug
      listen: 0.0.0.0
      port: 19090
      AllowAllUsers: true
      domains:
        - example.tld
        - ifauth.example.tld
        - vouch.example.tld
        - adfs.example.tld
      cookie: 
        name: VouchCookie
        domain: .example.tld
        secure: true
        httpOnly: true
      headers:
        jwt: X-Vouch-Token
        querystring: access_token
        redirect: X-Vouch-Requested-URI
        idToken: X-Vouch-IdP-IdToken
      session:
        name: VouchSession
      jwt:
        secret: Dg2t7sSoSm9X_rE8b3p7FP-cl_MZkmxXS4rLRZWi
        maxAge: 59
      db: 
        file: /db/vouch_bolt.db
    oauth:
      provider: adfs
      client_id: 9b31f91c-91da-47df-899f-e66c7b9cc2ef
      client_secret: Dg2t7sSoSm9X_rE8b3p7FP-cl_MZkmxXS4rLRZWi
      auth_url: https://adfs.example.tld/adfs/oauth2/authorize/
      token_url: https://adfs.example.tld/adfs/oauth2/token/
      scopes:
        - email
        - profile
        - openid
      callback_url: https://vouch.example.tld/auth
    
    

    Debug log:

    vouch_1  | {"level":"debug","ts":1580914641.1227398,"msg":"/login"}
    vouch_1  | {"level":"debug","ts":1580914641.1227658,"msg":"domain vouch.example.tld matched array value at [1]=vouch.example.tld"}
    vouch_1  | {"level":"debug","ts":1580914641.1227777,"msg":"setting the cookie domain to .example.tld"}
    vouch_1  | {"level":"debug","ts":1580914641.1227868,"msg":"deleting cookie: VouchCookie"}
    vouch_1  | {"level":"debug","ts":1580914641.1229758,"msg":"session state set to 9tQelOybfX2PZG8D4YFD9xpNSSKQI"}
    vouch_1  | {"level":"debug","ts":1580914641.1231618,"msg":"session requestedURL set to https://ifauth.example.tld/"}
    vouch_1  | {"level":"debug","ts":1580914641.1231718,"msg":"failcount for https://ifauth.example.tld/ is 0"}
    vouch_1  | {"level":"debug","ts":1580914641.1231768,"msg":"saving session"}
    vouch_1  | {"level":"debug","ts":1580914641.123265,"msg":"redirecting to oauthURL https://adfs.example.tld/adfs/oauth2/authorize/?client_id=9b31f91c-91da-47df-899f-e66c7b9cc2ef&redirect_uri=https%3A%2F%2Fvouch.example.tld%2Fauth&resource=https%3A%2F%2Fvouch.example.tld%2Fauth&response_type=code&scope=email+profile+openid&state=9tQelOybfX2PZG8D4YFD9xpNSSKQI"}
    vouch_1  | {"level":"debug","ts":1580914641.1232948,"msg":"CaptureWriter.Write set w.StatusCode 302"}
    vouch_1  | {"level":"debug","ts":1580914641.1233146,"msg":"Request handled successfully: 302"}
    vouch_1  | {"level":"info","ts":1580914641.123327,"msg":"|302|  578.493µs /login","statusCode":302,"request":44,"latency":0.000578493,"avgLatency":0.008567349,"ipPort":"127.0.0.1:47820","method":"GET","host":"vouch.example.tld","path":"/login","referer":"https://adfs.example.tld/adfs/oauth2/authorize/?client_id=9b31f91c-91da-47df-899f-e66c7b9cc2ef&redirect_uri=https%3A%2F%2Fvouch.example.tld%2Fauth&resource=https%3A%2F%2Fvouch.example.tld%2Fauth&response_type=code&scope=email+profile+openid&state=A9pWyOujA4537ZTYJwVHjzsuUSNd0H43"}
    vouch_1  | {"level":"debug","ts":1580914641.2798855,"msg":"Request received : &{GET /auth?error=server_error&error_description=MSIS9604%3a+An+error+occurred.+The+authorization+server+was+not+able+to+fulfill+the+request.&state=9tQelOybfX2PZG8D4YFD9xpNSSKQI&client-request-id=181468d2-825b-475b-b10b-0080020000fd HTTP/1.0 1 0 map[X-Aasaam-Agent-Vendor:[google] Connection:[close] Upgrade-Insecure-Requests:[1] Accept:[text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9] X-Real-Ip:[172.18.64.65] Cache-Control:[max-age=0] Sec-Fetch-User:[?1] Referer:[https://adfs.example.tld/adfs/oauth2/authorize/?client_id=9b31f91c-91da-47df-899f-e66c7b9cc2ef&redirect_uri=https%3A%2F%2Fvouch.example.tld%2Fauth&resource=https%3A%2F%2Fvouch.example.tld%2Fauth&response_type=code&scope=email+profile+openid&state=A9pWyOujA4537ZTYJwVHjzsuUSNd0H43] Cookie:[aasaam_cid=AAAAAMLXOl4HAGO2ASw0AA==; VouchSession=MTU4MDkxNDY0MXxEdi1CQkFFQ180SUFBUkFCRUFBQV82WF9nZ0FEQm5OMGNtbHVad3dPQUF4eVpYRjFaWE4wWldSVlVrd0djM1J5YVc1bkRCd0FHbWgwZEhCek9pOHZhV1poZFhSb0xtbDFiWE11WVdNdWFYSXZCbk4wY21sdVp3d2NBQnBvZEhSd2N6b3ZMMmxtWVhWMGFDNXBkVzF6TG1GakxtbHlMd05wYm5RRUFnQUNCbk4wY21sdVp3d0hBQVZ6ZEdGMFpRWnpkSEpwYm1jTUh3QWRPWFJSWld4UGVXSm1XREpRV2tjNFJEUlpSa1E1ZUhCT1UxTkxVVWs9fCMTy1z4jnswgoqxikyW9529Rsbb8CA-U1dwoN_IyIge] X-Forwarded-For:[172.18.64.65] X-Aasaam-Client-Id:[0d443f07] X-Aasaam-Agent-Hash:[807ca0a2] X-Aasaam-Geo-Country-Flag:[🌐] Sec-Fetch-Mode:[navigate] X-Request-Time:[1580914641.278] X-Aasaam-Agent-Category:[pc] User-Agent:[Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/79.0.3945.79 Chrome/79.0.3945.79 Safari/537.36] X-Forwarded-Port:[443] X-Forwarded-Proto:[https] X-Aasaam-Agent-Version:[79] Sec-Fetch-Site:[same-site] Accept-Encoding:[gzip, deflate, br] Accept-Language:[en-US,en;q=0.9,fa;q=0.8] X-Aasaam-Agent-Os:[linux] X-Request-Id:[ff60d561ffe9225726e66aceb148d9a3] X-Aasaam-Foreign-Referer-Host:[adfs.example.tld] X-Aasaam-Geo-Default-Lang-Direction:[ltr] X-Forwarded-Host:[vouch.example.tld] X-Aasaam-Client-New:[0] X-Aasaam-Agent-Name:[chrome]] {} <nil> 0 [] true vouch.example.tld map[] map[] <nil> map[] 127.0.0.1:47868 /auth?error=server_error&error_description=MSIS9604%3a+An+error+occurred.+The+authorization+server+was+not+able+to+fulfill+the+request.&state=9tQelOybfX2PZG8D4YFD9xpNSSKQI&client-request-id=181468d2-825b-475b-b10b-0080020000fd <nil> <nil> <nil> 0xc4201b8b70}"}
    vouch_1  | {"level":"debug","ts":1580914641.2799928,"msg":"/auth"}
    vouch_1  | {"level":"warn","ts":1580914641.2806106,"msg":"/auth Error state: server_error, Error description: MSIS9604: An error occurred. The authorization server was not able to fulfill the request."}
    vouch_1  | {"level":"debug","ts":1580914641.2806458,"msg":"CaptureWriter.Write set w.StatusCode 403"}
    vouch_1  | {"level":"debug","ts":1580914641.2807608,"msg":"Request handled successfully: 403"}
    vouch_1  | {"level":"info","ts":1580914641.2807925,"msg":"|403|  770.249µs /auth","statusCode":403,"request":45,"latency":0.000770249,"avgLatency":0.008394081,"ipPort":"127.0.0.1:47868","method":"GET","host":"vouch.example.tld","path":"/auth","referer":"https://adfs.example.tld/adfs/oauth2/authorize/?client_id=9b31f91c-91da-47df-899f-e66c7b9cc2ef&redirect_uri=https%3A%2F%2Fvouch.example.tld%2Fauth&resource=https%3A%2F%2Fvouch.example.tld%2Fauth&response_type=code&scope=email+profile+openid&state=A9pWyOujA4537ZTYJwVHjzsuUSNd0H43"}
    

    Screenshot from 2020-02-05 18-30-00

    question 
    opened by mhf-ir 27
  • new provider to support Aliyun iDaas / Alibaba OIDC (userInfo fix, should be easy)

    new provider to support Aliyun iDaas / Alibaba OIDC (userInfo fix, should be easy)

    here is my vouch proxy config https://gist.github.com/Gourds/354df4f711d1f394c925a3ddaf8e7754

    nginx vouch config: https://gist.github.com/Gourds/ae0fde3ecc24b6e0afd9165eac7e8874 nginx protect app config: https://gist.github.com/Gourds/915f2ddd96c6f6d4729165108d603ee3 here is vouch-proxy debug log https://gist.github.com/Gourds/844b7c5ed53c8790d7b151733ce4267f

    In debug mode, when i go to my protect site eg: http://test_sso_nginx_a.taiheops.com:2081 it will redirect to http://vouch.taiheops.com:2081/login?url=http://test_sso_nginx_a.taiheops.com:2081/&vouch-failcount=&X-Vouch-Token=&error= then, when i click login button , the return code is 400, click logout button, return msg is /logout you have been logged out, click validate buttion , return msg is no jwt found in request,

    I think there is a problem with my configuration, but I tried many methods, and I also read related issues and instructions and still can’t solve it.

    enhancement help wanted 
    opened by Gourds 25
  • transfer/fork vouch helm chart (Thank you Gavin for your years of support!!)

    transfer/fork vouch helm chart (Thank you Gavin for your years of support!!)

    👋 I think i'm shutting down my home k8s server and as such, kinda want to find owners for my helm charts. Are you willing to take it over? there's lots of github actions for publishing helm charts. Its been essentially no maintaince for a while now, but probably could get the version number updated more often.

    opened by halkeye 24
  • Azure Active Directory - External users

    Azure Active Directory - External users

    AAD external users cannot be authenticated An AAD user can authenticate, an external user within the same AAD is not able to autenticate.

    I've identified the behavior being an empty username/UserPrincipalName of external users in AAD.

    This is the log from vouch:

    azure GetUserInfo: User: &{Username:[email protected] Name:René Hézser Email:[email protected] CreatedOn:0 LastUpdate:0 ID:0 TeamMemberships:[]}
    verifyUser: Success! found user.Username in WhiteList: [email protected]"}
    
    azure GetUserInfo: User: &{Username: Name:René Hézser (MS) Email:[email protected] CreatedOn:0 LastUpdate:0 ID:0 TeamMemberships:[]}
    /auth Claims from userinfo: {Claims:map[email:[email protected]]}"}
    /auth User is not authorized: verifyUser: user.Username not found in WhiteList:  . Please try again or seek support from your administrator"}
    

    Using the Graph Explorer I can see that the userPrincipalName is null for an external user. If I look at the code, would it make sense to check for an empty Username again after this line and set it from the email property?

    Below is the result from Graph Explorer for 1) an AAD user and 2) an external account.

    {
        "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users('---')/people",
        "@odata.nextLink": "https://graph.microsoft.com/v1.0/me/people/?$search=rene&$skip=0",
        "value": [
            {
                "id": "---'",
                "displayName": "René Hézser",
                "givenName": "René",
                "surname": "Hézser",
                "birthday": null,
                "personNotes": null,
                "isFavorite": false,
                "jobTitle": null,
                "companyName": null,
                "yomiCompany": null,
                "department": null,
                "officeLocation": null,
                "profession": null,
                "userPrincipalName": "[email protected]",
                "imAddress": "sip:[email protected]",
                "scoredEmailAddresses": [
                    {
                        "address": "[email protected]",
                        "relevanceScore": 6,
                        "selectionLikelihood": "notSpecified"
                    }
                ],
                "phones": [---],
                "personType": {
                    "class": "Person",
                    "subclass": "OrganizationUser"
                }
            },
            {
                "id": "---",
                "displayName": "[email protected]",
                "givenName": null,
                "surname": null,
                "birthday": null,
                "personNotes": null,
                "isFavorite": false,
                "jobTitle": null,
                "companyName": null,
                "yomiCompany": null,
                "department": null,
                "officeLocation": null,
                "profession": null,
                "userPrincipalName": null,
                "imAddress": null,
                "scoredEmailAddresses": [
                    {
                        "address": "[email protected]",
                        "relevanceScore": -2,
                        "selectionLikelihood": "notSpecified"
                    }
                ],
                "phones": [],
                "personType": {
                    "class": "Person",
                    "subclass": "ImplicitContact"
                }
            }
        ]
    }
    

    Some more information from azure GetUserInfo: getting user info from accessToken:

    {
        "aud": "00000003-0000-0000-c000-000000000000",
        "iss": "https://sts.windows.net/---/",
        "iat": 1599826218,
        "nbf": 1599826218,
        "exp": 1599830118,
        "acct": 1,
        "acr": "1",
        "aio": "AUQAu/---==",
        "altsecid": "1:live.com:---",
        "amr": [
            "pwd"
        ],
        "app_displayname": "Homeserver",
        "appid": "---",
        "appidacr": "1",
        "email": "[email protected]",
        "family_name": "Hézser",
        "given_name": "René",
        "idp": "live.com",
        "idtyp": "user",
        "ipaddr": "---",
        "name": "René Hézser (MS)",
        "oid": "---",
        "platf": "3",
        "puid": "---",
        "rh": "0.---.",
        "scp": "email openid profile",
        "signin_state": [
            "kmsi"
        ],
        "sub": "lfi------------",
        "tenant_region_scope": "EU",
        "tid": "---",
        "unique_name": "live.com#[email protected]",
        "uti": "---",
        "ver": "1.0",
        "xms_st": {
            "sub": "----10P14Fck"
        },
        "xms_tcdt": 1345116819
    }
    
    enhancement help wanted 
    opened by ReneHezser 23
  • Too many redirects

    Too many redirects

    I apologise – I've read through just about all of the issues, perused the source and still can't nut this out. I think I'm losing my touch!

    My nginx configuration is shown below. My internal "protected" app and vouch are behind the same nginx proxy:

    server {
      listen 80;
      listen [::]:80;
      server_name cloud.reid.ee;
      return 301 https://$host$request_uri;
    }
    
    # Vouch
    
    server {
    	listen 443 ssl http2;
      listen [::]:443 ssl http2;
    	server_name vouch.reid.ee;
    	include /config/nginx/ssl.conf;
    	location / {
    		proxy_set_header Host vouch.reid.ee;
    		proxy_pass http://172.16.1.82:9090;
    	}
    }
    
    server {
    	listen 443 ssl http2 default_server;
    	listen [::]:443 ssl http2 default_server;
    	server_name cloud.reid.ee;
    	include /config/nginx/ssl.conf;
    	root /config/www;
    	index index.html index.htm index.php;
    	auth_request /validate;
    
    	location = /validate {
    		internal;
    		proxy_pass http://172.16.1.82:9090;
    		proxy_set_header Host cloud.reid.ee;
    		proxy_set_header Content-Length "";
    		proxy_pass_request_body off;
    		auth_request_set $auth_resp_x_vouch_user $upstream_http_x_vouch_user;
    		auth_request_set $auth_resp_jwt $upstream_http_x_vouch_jwt;
    		auth_request_set $auth_resp_err $upstream_http_x_vouch_err;
    		auth_request_set $auth_resp_failcount $upstream_http_x_vouch_failcount;
    	}
    
    	location /sonarr {
    		proxy_pass http://mogul.reid.ee:8989;
    		proxy_set_header X-Vouch-User $auth_resp_x_vouch_user;
    		auth_request_set $auth_resp_x_vouch_user $upstream_http_x_vouch_user;
    	}
    
    	error_page 401 = @error401;
    
    	location @error401 {
    		# redirect to Vouch Proxy for login
    		return 302 https://vouch.reid.ee/login?url=$scheme://$http_host$request_uri&vouch-failcount=$auth_resp_failcount&X-Vouch-Token=$auth_resp_jwt&error=$auth_resp_err;
    	}
    }
    

    My vouch config.yml is pretty straight-forward and it successfully interacts with Google:

    vouch:
      logLevel: debug
      listen: 0.0.0.0
      port: 9090
    
      domains:
      - reid.ee
    
      whiteList:
      - [email protected]
      - [email protected]
    
    oauth:
      provider: google
      client_id: xxxxx
      client_secret: xxxxx
      callback_urls:
      - https://vouch.reid.ee/auth
      preferredDomain: reid.ee
    

    When I hit my protected location, cloud.reid.ee/sonarr, I'm redirected via /validate to Google, where I'm successfully redirected back to vouch.reid.ee/auth. The logs seem to indicate that my session state is matched, the username is found in the whitelist and, hey, it should be happy days. It seems as though /auth responds with a 302 to /validate again, where my domain isn't seen as authorised, but also found as a matched array value:

    {"level":"debug","ts":1554723612.927297,"msg":"*ptokenCLaims: {[email protected] [] { 1554738012  0 Vouch 0 }}"}
    {"level":"info","ts":1554723612.9294083,"msg":"jwt cookie","username":"[email protected]"}
    {"level":"error","ts":1554723612.9306395,"msg":"http header 'Host: cloud.reid.ee' not authorized for configured `vouch.domains` (is Host being sent properly?)"}
    {"level":"debug","ts":1554723612.9322002,"msg":"domain cloud.reid.ee matched array value at [0]=reid.ee"}
    {"level":"debug","ts":1554723612.9332013,"msg":"CaptureWriter.Write set w.StatusCode Ƒ"}
    {"level":"debug","ts":1554723612.9341297,"msg":"Request handled successfully: 401"}
    

    Now, I've been trying all manner of variations on the setting the Host header theme as mentioned in README.md without success. I'm sorry to bother – but can you point me in the right direction?

    opened by andrewreid 22
  • Infinite Redirect

    Infinite Redirect

    Paste nginx config https://gist.github.com/eayin2/068b40e9a58e5546b8ffaebe228a177e vouch log https://gist.github.com/eayin2/7dd5cd4be7e6f7bed4acd53d593b1150 vouch config https://gist.github.com/eayin2/d458d5ebbf2441f6d50f66e4a337bbeb testing page: https://imgur.com/Z0uHWQV Okta.com (API) config https://gist.github.com/eayin2/bb7abd111449e74cccb9462b01535fd1

    Problem Infinite redirect loop after authentifcation. Redirect between vouch, my site and okta. Displays "Redirect Error" after login / or being logged in.

    Expected behavior Show my site after login (owncast)

    Desktop information:

    • OS: Ubuntu 20.04
    • Browser Chromium and Firefox
    • Version Chromium 90.0.4430.72 (Offizieller Build) (64-Bit)
    question 
    opened by eayin2 19
  • Add _FILE environment variable variants to read sensitive configuration from files

    Add _FILE environment variable variants to read sensitive configuration from files

    We're running Vouch in our Swarm cluster. All applications are configured from the CI deployment pipeline, and Vouch is no exception here. Currently, the JWT secret and OAuth provider configuration have to be passed as environment variables, which provides no protection for the values, so they are visible from internal monitoring dashboards which are accessible to all developers. We would like to restrict access to sensitive data like the OAuth client credentials however.

    This is easily possible by using Docker Secrets, which essentially mount secret values as files below /run/secret/. Lots of applications include support for ACME_SECRET and ACME_SECRET_FILE to allow passing the path of a file instead of the secret value itself.

    It would be great if Vouch supported _FILE variants of sensitive configuration settings, or maybe just all of them!

    In the mean time, there's a workaround: Dynamically generating a configuration file and providing that as a secret:

    services:
      vouch:
        environment:
          VOUCH_CONFIG: /config/dynamic_config.yaml
          # place other configuration here
        secrets:
          - source: vouch_config
            target: /config
    
    secrets:
      vouch_config:
        file: ./dynamic_config.yaml
    

    The configuration itself could be written using something like this in a build script:

    echo jwt.secret=$JWT_SECRET >> ./dynamic_config.yaml
    echo oauth.client_secret=$OAUTH_CLIENT_SECRET >> ./dynamic_config.yaml
    
    enhancement 
    opened by Radiergummi 2
  • Allow setting allowAllUsers: true without forcing cookie domain

    Allow setting allowAllUsers: true without forcing cookie domain

    Describe the problem We (Take Two) have hundreds of domains users authenticate to Okta with. Including all of these under Domains makes the cookie far too large, so right now we're forced to only allow a subset of users to authenticate with Vouch. Since we're only protecting an app that utilizes three domains, we really need to be able to set allowAllUsers: true while still having the cookie domain set via the callback url. A way to set multiple possible values for vouch.cookie.domain could also be a solution.

    Expected behavior Set allowAllUsers: true and provide a list of possible domains to vouch.cookie.domain instead of a single domain.

    Additional context We might be the largest org to utilize Vouch so far so we'd really like to see Vouch capable of operating at this scale. I'm sure this issue might come up for other larger orgs as well. Let me know your thoughts.

    I understand running a separate vouch instance for each domain in the app would also be a solution. We'd like to avoid doing that if possible as it would create a lot of overhead when adding new domains to the app in question.

    enhancement help wanted 
    opened by SimonLemaireT2 1
  • Add explanations about use of SameSite=strict to documentation

    Add explanations about use of SameSite=strict to documentation

    Describe the problem I had a setup using the GitHub provider which would return a 400 Bad Request after the redirect from github to /auth/{state}. This did not happen when using the links provided by the testing mode.

    I eventually narrowed this down to the fact I was using a server level proxy_cookie_flags ~ httponly secure samesite=strict; in my nginx config to prevent XSS attacks. Unfortunately, it's been long enough now that I don't remember why I did it.

    Removing samesite=strict and letting it default to lax dealt with the problem.

    Expected behavior It would be very helpful to have a few lines in the documentation for the vouch.cookie parameters explaining when you might use them, when you shouldn't use them and why it matters.

    question 
    opened by simonwgill 5
  • Azure SPN certificate client credential support

    Azure SPN certificate client credential support

    We are not allowed to use Azure SPN secret credential due to internal company policies. We can use only Azure SPN certificate credential.

    Currently, it seems that vouch-proxy only suppport secret credential for Azure oauth2 provider.

    Is there any plan / chance that certificate credential support will be implemented?

    Thank you!

    enhancement help wanted 
    opened by kasbst 1
  • Set the username to name in the ofchance that it is still blank

    Set the username to name in the ofchance that it is still blank

    Had an issue authenticating with personal Azure domain. Name was returned, but UPN and PreferredUsername was blank. This makes vouch fail with the error: "no User found in jwt" although authentication was successful.

    opened by vdbaan 0
  • Command line login using Authorization Code Flow

    Command line login using Authorization Code Flow

    Hi,

    Would It be possible to log against the vouch proxy from the command line, making a script like https://developer.okta.com/blog/2018/07/16/oauth-2-command-line and being able to obtain access_token(jwt) (using response headers like X-Vouch-IdP-IdToken, X-Vouch-IdP-AccessToken)?

    I see that /validate can also validate by access_token (as querystring) or Authentication Bearer (header):

    • https://github.com/vouch/vouch-proxy/blob/master/handlers/validate.go#L36
    • https://github.com/vouch/vouch-proxy/blob/master/pkg/jwtmanager/jwtmanager.go#L221

    It would be very useful for me to be able to make secure API requests from the console to the server bypassing the access_token(jwt) (instead of the browser cookie).

    Thanks in advance.

    enhancement help wanted 
    opened by sp-manuel-jurado 4
Owner
Vouch
Vouch
Demonstration of sharing secret data between an OAuth/OIDC client and an Identity Providers web client.

OAuth / OIDC Cubbyhole Share secret data between client applications. This is mostly a demonstration of some of the work I've been evaluating at Storj

mya 3 Mar 21, 2022
Lightweight SSO Login System

login Lightweight SSO Login System Convention Redirect to login.changkun.de?redirect=origin When login success, login.changkun.de will redirect to ori

Changkun Ou 4 Dec 1, 2021
Bui api login - Bui api login in golang

bui-api-login Project setup go mod tidy -compat=1.17 .env.local OAUTH2_REDIRECT

Vesko 0 Jan 7, 2022
Goauth: Pre-made OAuth/OpenIDConnect and general authorization hooks for webapp login

goauth Pre-made OAuth/OpenIDConnect and general authorization hooks for webapp login. Currently supports Google, Facebook and Microsoft "out of the bo

Steven Frew 0 Jan 28, 2022
sso, aka S.S.Octopus, aka octoboi, is a single sign-on solution for securing internal services

sso See our launch blog post for more information! Please take the SSO Community Survey to let us know how we're doing, and to help us plan our roadma

BuzzFeed 2.9k May 18, 2022
A collection of authentication Go packages related to OIDC, JWKs and Distributed Claims.

cap (collection of authentication packages) provides a collection of related packages which enable support for OIDC, JWT Verification and Distributed Claims.

HashiCorp 327 May 17, 2022
Jwtex - A serverless JWT exchanger and OIDC IdP

jwtex *This README is a work in progress jwtex is a serverless application that

Aidan Steele 25 Apr 22, 2022
Minting OIDC tokens from GitHub Actions for use with OpenFaaS

minty Experiment for minting OIDC tokens from GitHub Actions for use with OpenFaaS Why would you want this? Enable third-parties to deploy to your ope

Alex Ellis 9 Oct 31, 2021
Small library to make it easier to get a OIDC configuration

OIDC Discovery client This package covers two needs: Get the discovery document from some authority Get certificates from that authority Usage package

Martin Klingenberg 0 Nov 28, 2021
Server bridging Google's OAuth and service using Radius for authentication

Fringe Fringe is an easy workaround for Google Workplace users who need a Radius server to perform authentication on behalf of other services (e.g. 80

Pierre-Luc Simard 5 Mar 7, 2022
OauthMicroservice-cassandraCluster - Implement microservice of oauth using golang and cassandra to store user tokens

implement microservice of oauth using golang and cassandra to store user tokens

Mehdi 1 Jan 24, 2022
Provides AWS STS credentials based on Google Apps SAML SSO auth with interactive GUI support

What's this This command-line tool allows you to acquire AWS temporary (STS) credentials using Google Apps as a federated (Single Sign-On, or SSO) pro

Quan Hoang 30 Apr 29, 2022
Makes dealing with AWS SSO Logins an ease

go-aws-sso Make working with AWS SSO on local machines an ease. What is it about? Choose and retrieve short-living role credentials from all of your S

Tim Heurich 44 May 4, 2022
Home-sso-service - Single-Sign On service with golang

home-sso-service This is Single-Sign On service Dependencies go version go1.15.6

Nguyen Lam 1 May 10, 2022
A distribute SSO system

single-sign-on-system 一:SSO单点登录系统开发总结 (一):整体架构分析 基于go-oauth2/oauth2库实现的前端分离SSO单点登录系统 (二):系统技术点分析 当前系统的业务技术栈如下 Vue3 、ElementUI 作为前端页面 Nginx 用于解决系统之间的跨域

yinhuanyi 2 Feb 12, 2022
simple-jwt-provider - Simple and lightweight provider which exhibits JWTs, supports login, password-reset (via mail) and user management.

Simple and lightweight JWT-Provider written in go (golang). It exhibits JWT for the in postgres persisted user, which can be managed via api. Also, a password-reset flow via mail verification is available. User specific custom-claims also available for jwt-generation and mail rendering.

Max 24 Apr 25, 2022
:closed_lock_with_key: Middleware for keeping track of users, login states and permissions

Permissions2 Middleware for keeping track of users, login states and permissions. Online API Documentation godoc.org Features and limitations Uses sec

Alexander F. Rødseth 456 May 11, 2022
Go login handlers for authentication providers (OAuth1, OAuth2)

gologin Package gologin provides chainable login http.Handler's for Google, Github, Twitter, Facebook, Bitbucket, Tumblr, or any OAuth1 or OAuth2 auth

Dalton Hubble 1.5k May 4, 2022
JWT login microservice with plugable backends such as OAuth2, Google, Github, htpasswd, osiam, ..

loginsrv loginsrv is a standalone minimalistic login server providing a JWT login for multiple login backends. ** Attention: Update to v1.3.0 for Goog

tarent 1.9k May 6, 2022