https://github.com/oauth2-proxy/mockoidc
A Mock OIDC Server for Unit & Integration Tests
https://github.com/oauth2-proxy/mockoidc
golang oauth2 oidc
Last synced: 7 months ago
JSON representation
A Mock OIDC Server for Unit & Integration Tests
- Host: GitHub
- URL: https://github.com/oauth2-proxy/mockoidc
- Owner: oauth2-proxy
- License: mit
- Created: 2021-02-01T21:10:07.000Z (almost 5 years ago)
- Default Branch: main
- Last Pushed: 2024-02-16T22:23:30.000Z (over 1 year ago)
- Last Synced: 2025-03-24T11:13:13.309Z (8 months ago)
- Topics: golang, oauth2, oidc
- Language: Go
- Homepage:
- Size: 55.7 KB
- Stars: 80
- Watchers: 3
- Forks: 45
- Open Issues: 23
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# mockoidc
A Mock OpenID Connect Server for Authentication Unit and Integration Tests.
Created by @NickMeves and @egrif during the [Greenhouse Software](https://medium.com/in-the-weeds)
2021 Q1 Hack Day.
[](https://goreportcard.com/report/github.com/oauth2-proxy/mockoidc)
[](./LICENSE)
[](https://codeclimate.com/github/oauth2-proxy/mockoidc/maintainability)
[](https://codeclimate.com/github/oauth2-proxy/mockoidc/test_coverage)
## Usage
Import the package
```
import "github.com/oauth2-proxy/mockoidc"
```
Start the MockOIDC Server. This will spin up a minimal OIDC server in its own
goroutine. It will listen on localhost on a random port.
Then pull its configuration to integrate it with your application. Begin
testing!
```
m, _ := mockoidc.Run()
defer m.Shutdown()
cfg := m.Config()
// type Config struct {
// ClientID string
// ClientSecret string
// Issuer string
//
// AccessTTL time.Duration
// RefreshTTL time.Duration
// }
```
### RunTLS
Alternatively, if you provide your own `tls.Config`, the server can run with
TLS:
```
tlsConfig = &tls.Config{
// ...your TLS settings
}
m, _ := mockoidc.RunTLS(tlsConfig)
defer m.Shutdown()
```
### Endpoints
The following endpoints are implemented. They can either be pulled from the
OIDC discovery document (`m.Issuer() + "/.well-known/openid-configuration`)
or retrieved directly from the MockOIDC server.
```
m, _ := mockoidc.Run()
defer m.Shutdown()
m.Issuer()
m.DiscoveryEndpoint()
m.AuthorizationEndpoint()
m.TokenEndpoint()
m.UserinfoEndpoint()
m.JWKSEndpoint()
```
### Seeding Users and Codes
By default, calls to the `authorization_endpoint` will start a session as if
the `mockoidc.DefaultUser()` had logged in, and it will return a random code
for the `token_endpoint`. The User in the session started by this call to the
`authorization_endpoint` will be the one in the tokens returned by the
subsequent `token_endpoint` call.
These can be seeded with your own test Users & codes that will be returned:
```
m, _ := mockoidc.Run()
defer m.Shutdown()
user := &mockoidc.User{
// User details...
}
// Add the User to the queue, this will be returned by the next login
m.QueueUser(user)
// Preset the code returned by the next login
m.QueueCode("12345")
// ...Request to m.AuthorizationEndpoint()
```
### Forcing Errors
Arbitrary errors can also be queued for handlers to return instead of their
default behavior:
```
m, err := mockoidc.Run()
defer m.Shutdown()
m.QueueError(&mockoidc.ServerError{
Code: http.StatusInternalServerError,
Error: mockoidc.InternalServerError,
Description: "Some Custom Description",
})
```
### Manipulating Time
To accurately test token expiration scenarios, the MockOIDC server's view of
time is completely mutable.
You can override the server's view of `time.Now`
```
mockoidc.NowFunc = func() { //...custom logic }
```
As tests are running, you can fast-forward time to critical test points (e.g.
Access & Refresh Token expirations).
```
m, _ := mockoidc.Run()
m.FastForward(time.Duration(1) * time.Hour)
```
#### Synchronizing with `jwt-go` time
Even though we can fast-forward time, the underlying tokens processed by the
[jwt-go](https://github.com/dgrijalva/jwt-go) library still have timing logic.
We need to synchronize our timer with theirs:
```
m, _ := mockoidc.Run()
defer m.Shutdown()
// Overrides jwt.TimeFunc to m.Now
reset := m.Synchronize()
// reset is a mockoidc.ResetTime function that reverts jwt.TimeFunc to
// its original state
defer reset()
```
### Manual Configuration
Everything started up with `mockoidc.Run()` can be done manually giving the
opportunity to finely tune the settings:
```
// Create a fresh RSA Private Key for token signing
rsaKey, _ := rsa.GenerateKey(rand.Reader, 2048)
// Create an unstarted MockOIDC server
m, _ := mockoidc.NewServer(rsaKey)
// Create the net.Listener on the exact IP:Port you want
ln, _ := net.Listen("tcp", "127.0.0.1:8080")
tlsConfig = &tls.Config{
// ...your TLS settings
}
// tlsConfig can be nil if you want HTTP
m.Start(ln, tlsConfig)
defer m.Shutdown()
```
Nearly all the MockOIDC struct is public. If you want to update any settings
to predefined values (e.g. `clientID`, `clientSecret`, `AccessTTL`,
`RefreshTTL`) you can before calling `m.Start`.
Additional internal components of the MockOIDC server are public if you need
to tamper with them as well:
```
type MockOIDC struct {
// ...other stuff
// Normally, these would be private. Expose them publicly for
// power users.
Server *http.Server
Keypair *Keypair
SessionStore *SessionStore
UserQueue *UserQueue
ErrorQueue *ErrorQueue
}
```
#### Adding Middleware
When configuring the MockOIDC server manually, you have the opportunity to add
custom middleware before starting the server (e.g. request logging, test
validators, etc).
```
m, _ := mockoidc.NewServer(nil)
middleware := func(next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
// custom middleware logic here...
next.ServeHTTP(rw, req)
// custom middleware logic here...
})
}
m.AddMiddleware(middleware)
```