github.com/Richardknop/go-oauth2-server@v1.0.1/README.md (about)

     1  [1]: ../../../assets/blob/master/go-oauth2-server/login_screenshot.png
     2  [2]: ../../../assets/blob/master/go-oauth2-server/authorization_code_screenshot.png
     3  [3]: ../../../assets/blob/master/go-oauth2-server/implicit_screenshot.png
     4  [4]: http://patreon_public_assets.s3.amazonaws.com/sized/becomeAPatronBanner.png
     5  [5]: http://richardknop.com/images/btcaddress.png
     6  
     7  ## Go OAuth2 Server
     8  
     9  This service implements [OAuth 2.0 specification](http://tools.ietf.org/html/rfc6749#section-4.3). Excerpts from the specification are included in this README file to describe different grant types. Please read the full spec for more detailed information.
    10  
    11  [![Travis Status for RichardKnop/go-oauth2-server](https://travis-ci.org/RichardKnop/go-oauth2-server.svg?branch=master&label=linux+build)](https://travis-ci.org/RichardKnop/go-oauth2-server)
    12  [![godoc for RichardKnop/go-oauth2-server](https://godoc.org/github.com/nathany/looper?status.svg)](http://godoc.org/github.com/RichardKnop/go-oauth2-server)
    13  [![goreportcard for RichardKnop/go-oauth2-server](https://goreportcard.com/badge/github.com/RichardKnop/go-oauth2-server)](https://goreportcard.com/report/RichardKnop/go-oauth2-server)
    14  [![codecov for RichardKnop/go-oauth2-server](https://codecov.io/gh/RichardKnop/go-oauth2-server/branch/master/graph/badge.svg)](https://codecov.io/gh/RichardKnop/go-oauth2-server)
    15  
    16  [![Sourcegraph for RichardKnop/go-oauth2-server](https://sourcegraph.com/github.com/RichardKnop/go-oauth2-server/-/badge.svg)](https://sourcegraph.com/github.com/RichardKnop/go-oauth2-server?badge)
    17  [![Donate Bitcoin](https://img.shields.io/badge/donate-bitcoin-orange.svg)](https://richardknop.github.io/donate/)
    18  
    19  ---
    20  
    21  * [OAuth 2.0](#oauth-20)
    22    * [Client Authentication](#client-authentication)
    23    * [Grant Types](#grant-types)
    24      * [Authorization Code](#authorization-code)
    25      * [Implicit](#implicit)
    26      * [Resource Owner Password Credentials](#resource-owner-password-credentials)
    27      * [Client Credentials](#client-credentials)
    28    * [Refreshing An Access Token](#refreshing-an-access-token)
    29    * [Token Introspection](#token-introspection)
    30  * [Plugins](#plugins)
    31  * [Session Storage](#session-storage)
    32  * [Dependencies](#dependencies)
    33  * [Setup](#setup)
    34    * [etcd](#etcd)
    35    * [consul](#consul)
    36    * [postgres](#postgres)
    37  * [Compile & Run Data](#compile--run)
    38  * [Testing](#testing)
    39  * [Docker](#docker)
    40  * [Docker Compose](#docker-compose)
    41  * [Supporting the project](#supporting-the-project)
    42  
    43  ## OAuth 2.0
    44  
    45  ### Client Authentication
    46  
    47  http://tools.ietf.org/html/rfc6749#section-3.2.1
    48  
    49  Clients must authenticate with client credentials (client ID and secret) when issuing requests to `/v1/oauth/tokens` endpoint. Basic HTTP authentication should be used.
    50  
    51  ### Grant Types
    52  
    53  #### Authorization Code
    54  
    55  http://tools.ietf.org/html/rfc6749#section-4.1
    56  
    57  The authorization code grant type is used to obtain both access tokens and refresh tokens and is optimized for confidential clients. Since this is a redirection-based flow, the client must be capable of interacting with the resource owner's user-agent (typically a web browser) and capable of receiving incoming requests (via redirection) from the authorization server.
    58  
    59  ```
    60  +----------+
    61  | Resource |
    62  |   Owner  |
    63  |          |
    64  +----------+
    65       ^
    66       |
    67      (B)
    68  +----|-----+          Client Identifier      +---------------+
    69  |         -+----(A)-- & Redirection URI ---->|               |
    70  |  User-   |                                 | Authorization |
    71  |  Agent  -+----(B)-- User authenticates --->|     Server    |
    72  |          |                                 |               |
    73  |         -+----(C)-- Authorization Code ---<|               |
    74  +-|----|---+                                 +---------------+
    75    |    |                                         ^      v
    76   (A)  (C)                                        |      |
    77    |    |                                         |      |
    78    ^    v                                         |      |
    79  +---------+                                      |      |
    80  |         |>---(D)-- Authorization Code ---------'      |
    81  |  Client |          & Redirection URI                  |
    82  |         |                                             |
    83  |         |<---(E)----- Access Token -------------------'
    84  +---------+       (w/ Optional Refresh Token)
    85  ```
    86  
    87  The client initiates the flow by directing the resource owner's user-agent to the authorization endpoint. The client includes its client identifier, requested scope, local state, and a redirection URI to which the authorization server will send the user-agent back once access is granted (or denied).
    88  
    89  ```
    90  http://localhost:8080/web/authorize?client_id=test_client_1&redirect_uri=https%3A%2F%2Fwww.example.com&response_type=code&state=somestate&scope=read_write
    91  ```
    92  
    93  The authorization server authenticates the resource owner (via the user-agent).
    94  
    95  ![Log In page screenshot][1]
    96  
    97  The authorization server then establishes whether the resource owner grants or denies the client's access request.
    98  
    99  ![Authorize page screenshot][2]
   100  
   101  If the request fails due to a missing, invalid, or mismatching redirection URI, or if the client identifier is missing or invalid, the authorization server SHOULD inform the resource owner of the error and MUST NOT automatically redirect the user-agent to the invalid redirection URI.
   102  
   103  If the resource owner denies the access request or if the request fails for reasons other than a missing or invalid redirection URI, the authorization server informs the client by adding the error parameter to the query component of the redirection URI.
   104  
   105  ```
   106  https://www.example.com/?error=access_denied&state=somestate
   107  ```
   108  
   109  Assuming the resource owner grants access, the authorization server redirects the user-agent back to the client using the redirection URI provided earlier (in the request or during client registration). The redirection URI includes an authorization code and any local state provided by the client earlier.
   110  
   111  ```
   112  https://www.example.com/?code=7afb1c55-76e4-4c76-adb7-9d657cb47a27&state=somestate
   113  ```
   114  
   115  The client requests an access token from the authorization server's token endpoint by including the authorization code received in the previous step. When making the request, the client authenticates with the authorization server. The client includes the redirection URI used to obtain the authorization code for verification.
   116  
   117  ```sh
   118  curl --compressed -v localhost:8080/v1/oauth/tokens \
   119  	-u test_client_1:test_secret \
   120  	-d "grant_type=authorization_code" \
   121  	-d "code=7afb1c55-76e4-4c76-adb7-9d657cb47a27" \
   122  	-d "redirect_uri=https://www.example.com"
   123  ```
   124  The authorization server authenticates the client, validates the authorization code, and ensures that the redirection URI received matches the URI used to redirect the client before. If valid, the authorization server responds back with an access token and, optionally, a refresh token.
   125  
   126  ```json
   127  {
   128    "user_id": "1",
   129    "access_token": "00ccd40e-72ca-4e79-a4b6-67c95e2e3f1c",
   130    "expires_in": 3600,
   131    "token_type": "Bearer",
   132    "scope": "read_write",
   133    "refresh_token": "6fd8d272-375a-4d8a-8d0f-43367dc8b791"
   134  }
   135  ```
   136  
   137  #### Implicit
   138  
   139  http://tools.ietf.org/html/rfc6749#section-4.2
   140  
   141  The implicit grant type is used to obtain access tokens (it does not support the issuance of refresh tokens) and is optimized for public clients known to operate a particular redirection URI. These clients are typically implemented in a browser using a scripting language such as JavaScript.
   142  
   143  Since this is a redirection-based flow, the client must be capable of interacting with the resource owner's user-agent (typically a web browser) and capable of receiving incoming requests (via redirection) from the authorization server.
   144  
   145  Unlike the authorization code grant type, in which the client makes separate requests for authorization and for an access token, the client receives the access token as the result of the authorization request.
   146  
   147  The implicit grant type does not include client authentication, and relies on the presence of the resource owner and the registration of the redirection URI.  Because the access token is encoded into the redirection URI, it may be exposed to the resource owner and other applications residing on the same device.
   148  
   149  ```
   150  +----------+
   151  | Resource |
   152  |  Owner   |
   153  |          |
   154  +----------+
   155       ^
   156       |
   157      (B)
   158  +----|-----+          Client Identifier     +---------------+
   159  |         -+----(A)-- & Redirection URI --->|               |
   160  |  User-   |                                | Authorization |
   161  |  Agent  -|----(B)-- User authenticates -->|     Server    |
   162  |          |                                |               |
   163  |          |<---(C)--- Redirection URI ----<|               |
   164  |          |          with Access Token     +---------------+
   165  |          |            in Fragment
   166  |          |                                +---------------+
   167  |          |----(D)--- Redirection URI ---->|   Web-Hosted  |
   168  |          |          without Fragment      |     Client    |
   169  |          |                                |    Resource   |
   170  |     (F)  |<---(E)------- Script ---------<|               |
   171  |          |                                +---------------+
   172  +-|--------+
   173    |    |
   174   (A)  (G) Access Token
   175    |    |
   176    ^    v
   177  +---------+
   178  |         |
   179  |  Client |
   180  |         |
   181  +---------+
   182  ```
   183  
   184  The client initiates the flow by directing the resource owner's user-agent to the authorization endpoint. The client includes its client identifier, requested scope, local state, and a redirection URI to which the authorization server will send the user-agent back once access is granted (or denied).
   185  
   186  ```
   187  http://localhost:8080/web/authorize?client_id=test_client_1&redirect_uri=https%3A%2F%2Fwww.example.com&response_type=token&state=somestate&scope=read_write
   188  ```
   189  
   190  The authorization server authenticates the resource owner (via the user-agent).
   191  
   192  ![Log In page screenshot][1]
   193  
   194  The authorization server then establishes whether the resource owner grants or denies the client's access request.
   195  
   196  ![Authorize page screenshot][3]
   197  
   198  If the request fails due to a missing, invalid, or mismatching redirection URI, or if the client identifier is missing or invalid, the authorization server SHOULD inform the resource owner of the error and MUST NOT automatically redirect the user-agent to the invalid redirection URI.
   199  
   200  If the resource owner denies the access request or if the request fails for reasons other than a missing or invalid redirection URI, the authorization server informs the client by adding the following parameters to the fragment component of the redirection URI.
   201  
   202  ```
   203  https://www.example.com/#error=access_denied&state=somestate
   204  ```
   205  
   206  Assuming the resource owner grants access, the authorization server redirects the user-agent back to the client using the redirection URI provided earlier.  The redirection URI includes he access token in the URI fragment.
   207  
   208  ```
   209  https://www.example.com/#access_token=087902d5-29e7-417b-a339-b57a60d6742a&expires_in=3600&scope=read_write&state=somestate&token_type=Bearer
   210  ```
   211  
   212  The user-agent follows the redirection instructions by making a request to the web-hosted client resource (which does not include the fragment per [RFC2616]).  The user-agent retains the fragment information locally.
   213  
   214  The web-hosted client resource returns a web page (typically an HTML document with an embedded script) capable of accessing the full redirection URI including the fragment retained by the user-agent, and extracting the access token (and other parameters) contained in the fragment.
   215  
   216  The user-agent executes the script provided by the web-hosted client resource locally, which extracts the access token.
   217  
   218  The user-agent passes the access token to the client.
   219  
   220  #### Resource Owner Password Credentials
   221  
   222  http://tools.ietf.org/html/rfc6749#section-4.3
   223  
   224  The resource owner password credentials grant type is suitable in cases where the resource owner has a trust relationship with the client, such as the device operating system or a highly privileged application. The authorization server should take special care when enabling this grant type and only allow it when other flows are not viable.
   225  
   226  This grant type is suitable for clients capable of obtaining the resource owner's credentials (username and password, typically using an interactive form). It is also used to migrate existing clients using direct authentication schemes such as HTTP Basic or Digest authentication to OAuth by converting the stored credentials to an access token.
   227  
   228  ```
   229  +----------+
   230  | Resource |
   231  |  Owner   |
   232  |          |
   233  +----------+
   234       v
   235       |    Resource Owner
   236       (A) Password Credentials
   237       |
   238       v
   239  +---------+                                  +---------------+
   240  |         |>--(B)---- Resource Owner ------->|               |
   241  |         |         Password Credentials     | Authorization |
   242  | Client  |                                  |     Server    |
   243  |         |<--(C)---- Access Token ---------<|               |
   244  |         |    (w/ Optional Refresh Token)   |               |
   245  +---------+                                  +---------------+
   246  
   247  ```
   248  
   249  The resource owner provides the client with its username and password.
   250  
   251  The client requests an access token from the authorization server's token endpoint by including the credentials received from the resource owner. When making the request, the client authenticates with the authorization server.
   252  
   253  ```sh
   254  curl --compressed -v localhost:8080/v1/oauth/tokens \
   255  	-u test_client_1:test_secret \
   256  	-d "grant_type=password" \
   257  	-d "username=test@user" \
   258  	-d "password=test_password" \
   259  	-d "scope=read_write"
   260  ```
   261  
   262  The authorization server authenticates the client and validates the resource owner credentials, and if valid, issues an access token.
   263  
   264  ```json
   265  {
   266    "user_id": "1",
   267    "access_token": "00ccd40e-72ca-4e79-a4b6-67c95e2e3f1c",
   268    "expires_in": 3600,
   269    "token_type": "Bearer",
   270    "scope": "read_write",
   271    "refresh_token": "6fd8d272-375a-4d8a-8d0f-43367dc8b791"
   272  }
   273  ```
   274  
   275  #### Client Credentials
   276  
   277  http://tools.ietf.org/html/rfc6749#section-4.4
   278  
   279  The client can request an access token using only its client credentials (or other supported means of authentication) when the client is requesting access to the protected resources under its control, or those of another resource owner that have been previously arranged with the authorization server (the method of which is beyond the scope of this specification).
   280  
   281  The client credentials grant type MUST only be used by confidential clients.
   282  
   283  ```
   284  +---------+                                  +---------------+
   285  |         |                                  |               |
   286  |         |>--(A)- Client Authentication --->| Authorization |
   287  | Client  |                                  |     Server    |
   288  |         |<--(B)---- Access Token ---------<|               |
   289  |         |                                  |               |
   290  +---------+                                  +---------------+
   291  ```
   292  
   293  The client authenticates with the authorization server and requests an access token from the token endpoint.
   294  
   295  ```sh
   296  curl --compressed -v localhost:8080/v1/oauth/tokens \
   297  	-u test_client_1:test_secret \
   298  	-d "grant_type=client_credentials" \
   299  	-d "scope=read_write"
   300  ```
   301  
   302  The authorization server authenticates the client, and if valid, issues an access token.
   303  
   304  ```json
   305  {
   306    "access_token": "00ccd40e-72ca-4e79-a4b6-67c95e2e3f1c",
   307    "expires_in": 3600,
   308    "token_type": "Bearer",
   309    "scope": "read_write",
   310    "refresh_token": "6fd8d272-375a-4d8a-8d0f-43367dc8b791"
   311  }
   312  ```
   313  
   314  ### Refreshing An Access Token
   315  
   316  http://tools.ietf.org/html/rfc6749#section-6
   317  
   318  If the authorization server issued a refresh token to the client, the client can make a refresh request to the token endpoint in order to refresh the access token.
   319  
   320  ```sh
   321  curl --compressed -v localhost:8080/v1/oauth/tokens \
   322  	-u test_client_1:test_secret \
   323  	-d "grant_type=refresh_token" \
   324  	-d "refresh_token=6fd8d272-375a-4d8a-8d0f-43367dc8b791"
   325  ```
   326  
   327  The authorization server MUST:
   328  
   329  * require client authentication for confidential clients or for any client that was issued client credentials (or with other authentication requirements),
   330  
   331  * authenticate the client if client authentication is included and ensure that the refresh token was issued to the authenticated client, and
   332  
   333  * validate the refresh token.
   334  
   335  If valid and authorized, the authorization server issues an access token.
   336  
   337  ```json
   338  {
   339    "user_id": "1",
   340    "access_token": "1f962bd5-7890-435d-b619-584b6aa32e6c",
   341    "expires_in": 3600,
   342    "token_type": "Bearer",
   343    "scope": "read_write",
   344    "refresh_token": "3a6b45b8-9d29-4cba-8a1b-0093e8a2b933"
   345  }
   346  ```
   347  
   348  The authorization server MAY issue a new refresh token, in which case the client MUST discard the old refresh token and replace it with the new refresh token.  The authorization server MAY revoke the old refresh token after issuing a new refresh token to the client.  If a new refresh token is issued, the refresh token scope MUST be identical to that of the refresh token included by the client in the request.
   349  
   350  ### Token Introspection
   351  
   352  https://tools.ietf.org/html/rfc7662
   353  
   354  If the authorization server issued a access token or refresh token to the client, the client can make a request to the introspect endpoint in order to learn meta-information about a token.
   355  
   356  ```sh
   357  curl --compressed -v localhost:8080/v1/oauth/introspect \
   358  	-u test_client_1:test_secret \
   359  	-d "token=00ccd40e-72ca-4e79-a4b6-67c95e2e3f1c" \
   360  	-d "token_type_hint=access_token"
   361  ```
   362  
   363  The authorization server responds meta-information about a token.
   364  
   365  ```json
   366  {
   367    "active": true,
   368    "scope": "read_write",
   369    "client_id": "test_client_1",
   370    "username": "test@username",
   371    "token_type": "Bearer",
   372    "exp": 1454868090
   373  }
   374  ```
   375  
   376  ## Plugins
   377  
   378  This server is easily extended or modified through the use of plugins. Four services, [health](https://github.com/RichardKnop/go-oauth2-server/tree/master/health), [oauth](https://github.com/RichardKnop/go-oauth2-server/tree/master/oauth), [session](https://github.com/RichardKnop/go-oauth2-server/tree/master/session) and [web](https://github.com/RichardKnop/go-oauth2-server/tree/master/web) are available for modification.
   379  
   380  In order to implement a plugin:
   381  1. Create your own interface that implements all of methods of the service you are replacing.
   382  2. Modify `cmd/run_server.go` to use your service by calling the `session.Use[service-you-are-replaceing]Service(yourCustomService.NewService())` before the services are initialized via `services.Init(cnf, db)`.
   383  
   384  For example, to implement an available [redis session storage plugin](https://github.com/adam-hanna/redis-sessions):
   385  
   386  ~~~go
   387  // $ go get https://github.com/adam-hanna/redis-sessions
   388  //
   389  // cmd/run_server.go
   390  import (
   391      ...
   392      "github.com/adam-hanna/redis-sessions/redis"
   393      ...
   394  )
   395  
   396  // RunServer runs the app
   397  func RunServer(configBackend string) error {
   398      ...
   399  
   400      // configure redis for session store
   401      sessionSecrets := make([][]byte, 1)
   402      sessionSecrets[0] = []byte(cnf.Session.Secret)
   403      redisConfig := redis.ConfigType{
   404          Size:           10,
   405          Network:        "tcp",
   406          Address:        ":6379",
   407          Password:       "",
   408          SessionSecrets: sessionSecrets,
   409      }
   410  
   411      // start the services
   412      services.UseSessionService(redis.NewService(cnf, redisConfig))
   413      if err := services.InitServices(cnf, db); err != nil {
   414          return err
   415      }
   416      defer services.CloseServices()
   417  
   418      ...
   419  }
   420  ~~~
   421  
   422  ## Session Storage
   423  
   424  By default, this server implements in-memory, cookie sessions via [gorilla sessions](https://github.com/gorilla/sessions).
   425  
   426  However, because the session service can be replaced via a plugin, any of the available [gorilla sessions store implementations](https://github.com/gorilla/sessions#store-implementations) can be wrapped by `session.ServiceInterface`.
   427  
   428  ## Dependencies
   429  
   430  According to [Go 1.5 Vendor experiment](https://docs.google.com/document/d/1Bz5-UB7g2uPBdOx-rw5t9MxJwkfpx90cqG9AFL0JAYo), all dependencies are stored in the vendor directory. This approach is called `vendoring` and is the best practice for Go projects to lock versions of dependencies in order to achieve reproducible builds.
   431  
   432  This project uses [dep](https://github.com/golang/dep) for dependency management. To update dependencies during development:
   433  
   434  ```sh
   435  dep ensure
   436  ```
   437  
   438  ## Setup
   439  
   440  For distributed config storage you can use either etcd or consul (etcd being the default)
   441  
   442  If you are developing on OSX, install `etcd` or `consul`, `Postgres` and `nats-streaming-server`:
   443  
   444  ### etcd
   445  
   446  ```sh
   447  brew install etcd
   448  ```
   449  
   450  Load a development configuration into `etcd`:
   451  
   452  ```sh
   453  ETCDCTL_API=3 etcdctl put /config/go_oauth2_server.json '{
   454    "Database": {
   455      "Type": "postgres",
   456      "Host": "localhost",
   457      "Port": 5432,
   458      "User": "go_oauth2_server",
   459      "Password": "",
   460      "DatabaseName": "go_oauth2_server",
   461      "MaxIdleConns": 5,
   462      "MaxOpenConns": 5
   463    },
   464    "Oauth": {
   465      "AccessTokenLifetime": 3600,
   466      "RefreshTokenLifetime": 1209600,
   467      "AuthCodeLifetime": 3600
   468    },
   469    "Session": {
   470      "Secret": "test_secret",
   471      "Path": "/",
   472      "MaxAge": 604800,
   473      "HTTPOnly": true
   474    },
   475    "IsDevelopment": true
   476  }'
   477  ```
   478  
   479  If you are using etcd API version 3, use `etcdctl put` instead of `etcdctl set`.
   480  
   481  Check the config was loaded properly:
   482  
   483  ```sh
   484  etcdctl get /config/go_oauth2_server.json
   485  ```
   486  
   487  ### consul
   488  
   489  ```sh
   490  brew install consul
   491  ```
   492  
   493  Load a development configuration into `consul`:
   494  
   495  ```sh
   496  consul kv put /config/go_oauth2_server.json '{
   497    "Database": {
   498      "Type": "postgres",
   499      "Host": "localhost",
   500      "Port": 5432,
   501      "User": "go_oauth2_server",
   502      "Password": "",
   503      "DatabaseName": "go_oauth2_server",
   504      "MaxIdleConns": 5,
   505      "MaxOpenConns": 5
   506    },
   507    "Oauth": {
   508      "AccessTokenLifetime": 3600,
   509      "RefreshTokenLifetime": 1209600,
   510      "AuthCodeLifetime": 3600
   511    },
   512    "Session": {
   513      "Secret": "test_secret",
   514      "Path": "/",
   515      "MaxAge": 604800,
   516      "HTTPOnly": true
   517    },
   518    "IsDevelopment": true
   519  }'
   520  ```
   521  
   522  Check the config was loaded properly:
   523  
   524  ```sh
   525  consul kv get /config/go_oauth2_server.json
   526  ```
   527  
   528  ### Postgres
   529  
   530  ```sh
   531  brew install postgres
   532  ```
   533  
   534  You might want to create a `Postgres` database:
   535  
   536  ```sh
   537  createuser --createdb go_oauth2_server
   538  createdb -U go_oauth2_server go_oauth2_server
   539  ```
   540  
   541  ## Compile & Run
   542  
   543  Compile the app:
   544  
   545  ```sh
   546  go install .
   547  ```
   548  
   549  The binary accepts an optional flag of `--configBackend` which can be set to `etcd | consul`, defaults to `etcd`
   550  
   551  Run migrations:
   552  
   553  ```sh
   554  go-oauth2-server migrate
   555  ```
   556  
   557  And finally, run the app:
   558  
   559  ```sh
   560  go-oauth2-server runserver
   561  ```
   562  
   563  When deploying, you can set etcd related environment variables:
   564  
   565  * `ETCD_ENDPOINTS`
   566  * `ETCD_CERT_FILE`
   567  * `ETCD_KEY_FILE`
   568  * `ETCD_CA_FILE`
   569  * `ETCD_CONFIG_PATH`
   570  
   571  You can also set consul related variables
   572  
   573  * `CONSUL_ENDPOINT`
   574  * `CONSUL_CERT_FILE`
   575  * `CONSUL_KEY_FILE`
   576  * `CONSUL_CA_FILE`
   577  * `CONSUL_CONFIG_PATH`
   578  
   579  and the equivalent above commands would be
   580  
   581  ```sh
   582  go-oauth2-server --configBackend consul migrate
   583  ```
   584  ```sh
   585  go-oauth2-server --configBackend consul runserver
   586  ```
   587  
   588  ## Testing
   589  
   590  I have used a mix of unit and functional tests so you need to have `sqlite` installed in order for the tests to run successfully as the suite creates an in-memory database.
   591  
   592  To run tests:
   593  
   594  ```sh
   595  make test
   596  ```
   597  
   598  ## Docker
   599  
   600  Build a Docker image and run the app in a container:
   601  
   602  ```sh
   603  docker build -t go-oauth2-server:latest .
   604  docker run -e ETCD_ENDPOINTs=localhost:2379 -p 8080:8080 --name go-oauth2-server go-oauth2-server:latest
   605  ```
   606  
   607  You can load fixtures with `docker exec` command:
   608  
   609  ```sh
   610  docker exec <container_id> /go/bin/go-oauth2-server loaddata \
   611    oauth/fixtures/scopes.yml \
   612    oauth/fixtures/roles.yml \
   613    oauth/fixtures/test_clients.yml
   614  ```
   615  
   616  ## Docker Compose
   617  
   618  You can use [docker-compose](https://docs.docker.com/compose/) to start the app, postgres, etcd in separate linked containers:
   619  
   620  ```sh
   621  docker-compose up
   622  ```
   623  
   624  During `docker-compose up` process all configuration and fixtures will be loaded. After successful up you can check, that app is running using for example the health check request:
   625  
   626  ```sh
   627  curl --compressed -v localhost:8080/v1/health
   628  ```
   629  
   630  ## Supporting the project
   631  
   632  Become a patreon:
   633  
   634  [![http://patreon.com/richardknop][4]](http://patreon.com/richardknop)
   635  
   636  Or donate BTC to my wallet: `12iFVjQ5n3Qdmiai4Mp9EG93NSvDipyRKV`
   637  
   638  ![Donate BTC][5]