{"id":13538468,"url":"https://github.com/navikt/mock-oauth2-server","last_synced_at":"2026-05-06T22:12:40.829Z","repository":{"id":36958863,"uuid":"235432421","full_name":"navikt/mock-oauth2-server","owner":"navikt","description":"A scriptable/customizable web server for testing HTTP clients using OAuth2/OpenID Connect or applications with a dependency to a running OAuth2 server (i.e. APIs requiring signed JWTs from a known issuer)","archived":false,"fork":false,"pushed_at":"2026-05-06T20:52:58.000Z","size":6389,"stargazers_count":374,"open_issues_count":8,"forks_count":69,"subscribers_count":7,"default_branch":"master","last_synced_at":"2026-05-06T21:41:15.875Z","etag":null,"topics":["authorization-server","docker","java","junit5","jwt","kotlin","mock","mock-oauth2-server","nav-authnz","oauth2","oidc","openid-connect","security","token","tokens"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/navikt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2020-01-21T20:12:30.000Z","updated_at":"2026-05-06T20:48:59.000Z","dependencies_parsed_at":"2023-10-23T07:35:45.524Z","dependency_job_id":"31775526-47e0-4124-a5f6-39e9ceca6973","html_url":"https://github.com/navikt/mock-oauth2-server","commit_stats":null,"previous_names":[],"tags_count":91,"template":false,"template_full_name":null,"purl":"pkg:github/navikt/mock-oauth2-server","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/navikt%2Fmock-oauth2-server","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/navikt%2Fmock-oauth2-server/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/navikt%2Fmock-oauth2-server/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/navikt%2Fmock-oauth2-server/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/navikt","download_url":"https://codeload.github.com/navikt/mock-oauth2-server/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/navikt%2Fmock-oauth2-server/sbom","scorecard":{"id":676577,"data":{"date":"2025-08-11","repo":{"name":"github.com/navikt/mock-oauth2-server","commit":"2c7a77305feff178887e8930c21b81d52588b85a"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":5.9,"checks":[{"name":"Maintained","score":8,"reason":"10 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 8","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":3,"reason":"Found 4/11 approved changesets -- score normalized to 3","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":9,"reason":"binaries present in source code","details":["Warn: binary detected: gradle/wrapper/gradle-wrapper.jar:1"],"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: jobLevel 'contents' permission set to 'write': .github/workflows/build-master.yml:12","Warn: jobLevel 'packages' permission set to 'write': .github/workflows/build-master.yml:11","Warn: jobLevel 'contents' permission set to 'write': .github/workflows/build-master.yml:31","Warn: jobLevel 'packages' permission set to 'write': .github/workflows/dokka.yml:15","Warn: jobLevel 'contents' permission set to 'write': .github/workflows/dokka.yml:14","Info: jobLevel 'contents' permission set to 'read': .github/workflows/publish-release.yml:14","Warn: no topLevel permission defined: .github/workflows/active-issue-pr.yml:1","Info: topLevel 'contents' permission set to 'read': .github/workflows/build-master.yml:7","Warn: topLevel 'contents' permission set to 'write': .github/workflows/dokka.yml:8","Warn: no topLevel permission defined: .github/workflows/manual_testing.yml:1","Warn: no topLevel permission defined: .github/workflows/publish-release.yml:1","Warn: topLevel 'contents' permission set to 'write': .github/workflows/test-dp-pr.yaml:10","Warn: no topLevel permission defined: .github/workflows/test-pr.yaml:1"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Pinned-Dependencies","score":3,"reason":"dependency not pinned by hash detected -- score normalized to 3","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/active-issue-pr.yml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/navikt/mock-oauth2-server/active-issue-pr.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/dokka.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/navikt/mock-oauth2-server/dokka.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/dokka.yml:21: update your workflow using https://app.stepsecurity.io/secureworkflow/navikt/mock-oauth2-server/dokka.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/dokka.yml:34: update your workflow using https://app.stepsecurity.io/secureworkflow/navikt/mock-oauth2-server/dokka.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/manual_testing.yml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/navikt/mock-oauth2-server/manual_testing.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/manual_testing.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/navikt/mock-oauth2-server/manual_testing.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/publish-release.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/navikt/mock-oauth2-server/publish-release.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/publish-release.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/navikt/mock-oauth2-server/publish-release.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/publish-release.yml:29: update your workflow using https://app.stepsecurity.io/secureworkflow/navikt/mock-oauth2-server/publish-release.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test-dp-pr.yaml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/navikt/mock-oauth2-server/test-dp-pr.yaml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test-dp-pr.yaml:21: update your workflow using https://app.stepsecurity.io/secureworkflow/navikt/mock-oauth2-server/test-dp-pr.yaml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/test-dp-pr.yaml:37: update your workflow using https://app.stepsecurity.io/secureworkflow/navikt/mock-oauth2-server/test-dp-pr.yaml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test-pr.yaml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/navikt/mock-oauth2-server/test-pr.yaml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test-pr.yaml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/navikt/mock-oauth2-server/test-pr.yaml/master?enable=pin","Info:   2 out of  13 GitHub-owned GitHubAction dependencies pinned","Info:   3 out of   6 third-party GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE.md:0","Info: FSF or OSI recognized license: MIT License: LICENSE.md:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Packaging","score":10,"reason":"packaging workflow detected","details":["Info: Project packages its releases by way of GitHub Actions.: .github/workflows/publish-release.yml:11"],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Security-Policy","score":9,"reason":"security policy file detected","details":["Info: security policy file detected: github.com/navikt/.github/SECURITY.md:1","Info: Found linked content: github.com/navikt/.github/SECURITY.md:1","Warn: One or no descriptive hints of disclosure, vulnerability, and/or timelines in security policy","Info: Found text in security policy: github.com/navikt/.github/SECURITY.md:1"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 26 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-21T21:41:16.735Z","repository_id":36958863,"created_at":"2025-08-21T21:41:16.735Z","updated_at":"2025-08-21T21:41:16.735Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32713978,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-06T19:35:05.142Z","status":"ssl_error","status_checked_at":"2026-05-06T19:35:03.996Z","response_time":117,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["authorization-server","docker","java","junit5","jwt","kotlin","mock","mock-oauth2-server","nav-authnz","oauth2","oidc","openid-connect","security","token","tokens"],"created_at":"2024-08-01T09:01:12.378Z","updated_at":"2026-05-06T22:12:40.812Z","avatar_url":"https://github.com/navikt.png","language":"Kotlin","funding_links":[],"categories":["Kotlin","测试"],"sub_categories":[],"readme":"[![Build](https://github.com/navikt/mock-oauth2-server/workflows/Build%20master/badge.svg)](https://github.com/navikt/mock-oauth2-server/actions) [![Maven Central](https://img.shields.io/maven-central/v/no.nav.security/mock-oauth2-server?color=green\u0026logo=Apache%20Maven)](https://search.maven.org/artifact/no.nav.security/mock-oauth2-server) \n\n# mock-oauth2-server\nA scriptable/customizable web server for testing HTTP clients using OAuth2/OpenID Connect or applications with a dependency to a running OAuth2 server (i.e. APIs requiring signed JWTs from a known issuer).  The server also provides the necessary endpoints for token validation (endpoint for JWKS) and ID Provider metadata discovery (\"well-known\" endpoints providing  server metadata)\n\n**mock-oauth2-server** is written in Kotlin using the great [OkHttp MockWebServer](https://github.com/square/okhttp/tree/master/mockwebserver) as the underlying server library and can be used in unit/integration tests in both **Java** and **Kotlin** or in any language as a standalone server in e.g. docker-compose.\n\nEven though the server aims to be compliant with regards to the supported OAuth2/OpenID Connect specifications, you should never use it for anything else than tests. That being said, when developing OAuth2 clients you should always verify that the expected requests are being made in your tests.\n\n## Motivation\n\nThe motivation behind this library is to provide a setup such that application developers don't feel the need to disable security in their apps when running tests! If you have any issues with regards to OAuth2 and tokens et. al. and consider to disable \"security\" when running tests please submit an issue or a PR so that we can all help developers and security to live in harmony once again (if ever..)!\n\n## Features\n\n* **Multi-issuer/Multi-tenancy support**: the server can represent as many different Identity Providers/Token Issuers as you need (with different token issuer names) WITHOUT any setup!\n* **Implements OAuth2/OpenID Connect grants/flows**\n  * OpenID Connect Authorization Code Flow\n  * OAuth2 Client Credentials Grant\n  * OAuth2 JWT Bearer Grant (On-Behalf-Of flow)\n  * OAuth2 Token Exchange Grant\n  * OAuth2 Refresh Token Grant\n  * OAuth2 Resource Owner Password Credentials (Password Grant)\n    * *usage should be avoided if possible as this grant is considered insecure and [removed in its entirety](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics-13#section-3.4) from OAuth 2.1*\n* **Issued JWT tokens are verifiable** through standard mechanisms with OpenID Connect Discovery / OAuth2 Authorization Server Metadata\n* **Unit/Integration test support**\n  * Start and stop server for each test\n  * Sane defaults with minimal setup if you don't need token customization\n  * Enqueue expected tokens if you need to customize token claims\n  * Enqueue expected responses\n  * Verify expected requests made to the server\n  * Customizable through exposure of underlying  [OkHttp MockWebServer](https://github.com/square/okhttp/tree/master/mockwebserver) \n* **Standalone support** - i.e. run as application in IDE, run inside your app, or as a Docker image (provided)\n* **OAuth2 Client Debugger** - e.g. support for triggering OIDC Auth Code Flow and receiving callback in debugger app, view token response from server (intended for standalone support)\n\n## API Documentation\n\n[mock-oauth2-server](https://navikt.github.io/mock-oauth2-server/)\n\n## 📦 Install\n\n**Gradle Kotlin DSL**\n\nLatest version [![Maven Central](https://img.shields.io/maven-central/v/no.nav.security/mock-oauth2-server?color=green\u0026logo=Apache%20Maven)](https://search.maven.org/artifact/no.nav.security/mock-oauth2-server)\n\n```kotlin\ntestImplementation(\"no.nav.security:mock-oauth2-server:$mockOAuth2ServerVersion\")\n```\n\n**Maven**\n\nLatest version [![Maven Central](https://img.shields.io/maven-central/v/no.nav.security/mock-oauth2-server?color=green\u0026logo=Apache%20Maven)](https://search.maven.org/artifact/no.nav.security/mock-oauth2-server)\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003eno.nav.security\u003c/groupId\u003e\n  \u003cartifactId\u003emock-oauth2-server\u003c/artifactId\u003e\n  \u003cversion\u003e${mock-oauth2-server.version}\u003c/version\u003e\n  \u003cscope\u003etest\u003c/scope\u003e\n\u003c/dependency\u003e\n```\n\n**Docker**\n\nLatest version [![GitHub release (latest SemVer including pre-releases)](https://img.shields.io/github/v/release/navikt/mock-oauth2-server?color=green\u0026include_prereleases\u0026label=GitHub%20Package%20Registry\u0026logo=Docker)](https://github.com/navikt/mock-oauth2-server/packages/)\n\n```\ndocker pull ghcr.io/navikt/mock-oauth2-server:$MOCK_OAUTH2_SERVER_VERSION\n```\n\n\n\n## ⌨️ Usage\n\n### Well-Known Configuration\n\nThe **mock-oauth2-server** will supply different configurations depending on the url used against the server, more specifically the first **path** (or context root) element in your request url will specify the `issuerId`.\n\nA request to `http://localhost:8080/default/.well-known/openid-configuration` will yield an `issuerId` of `default` with the following configuration:\n\n```json\n{\n   \"issuer\":\"http://localhost:8080/default\",\n   \"authorization_endpoint\":\"http://localhost:8080/default/authorize\",\n   \"end_session_endpoint\" : \"http://localhost:8080/default/endsession\",\n   \"revocation_endpoint\" : \"http://localhost:8080/default/revoke\",\n   \"token_endpoint\":\"http://localhost:8080/default/token\",\n   \"userinfo_endpoint\":\"http://localhost:8080/default/userinfo\",\n   \"jwks_uri\":\"http://localhost:8080/default/jwks\",\n   \"introspection_endpoint\":\"http://localhost:8080/default/introspect\",\n   \"response_types_supported\":[\n     \"code\",\n     \"none\",\n     \"id_token\",\n     \"token\"\n   ],\n   \"response_modes_supported\":[\n     \"query\",\n     \"fragment\",\n     \"form_post\"\n   ],\n   \"subject_types_supported\":[\n     \"public\"\n   ],\n   \"id_token_signing_alg_values_supported\":[\n     \"ES256\",\n     \"ES384\",\n     \"RS256\",\n     \"RS384\",\n     \"RS512\",\n     \"PS256\",\n     \"PS384\",\n     \"PS512\"\n   ],\n   \"code_challenge_methods_supported\":[\n     \"plain\", \n     \"S256\" \n   ]\n}\n```\n\nThe actual issuer value in a JWT will be `iss: \"http://localhost:8080/default\"`\n\nTo use another issuer with id `anotherissuer` simply make a request to `http://localhost:8080/anotherissuer/.well-known/openid-configuration` and the configuration will change accordingly.\n\n### Unit tests\n\n##### Setup test\n\n* Start the server at a random port\n* Get url for server metadata/configuration\n* Setup your app to use the OAuth2 server metadata and conduct your tests\n* Shutdown the server\n\n```kotlin\nval server = MockOAuth2Server()\nserver.start()\n// Can be anything you choose - should uniquely identify your issuer if you have several\nval issuerId = \"default\"\n// Discovery url to authorization server metadata\nval wellKnownUrl = server.wellKnownUrl(issuerId).toString()\n// ......\n// Setup your app with metadata from wellKnownUrl and do your testing here\n// ......\nserver.shutdown()\n```\n\n##### Testing an app requiring user login with OpenID Connect Authorization Code Flow\n\n* Setup test like above\n* Make your test HTTP client follow redirects\n* Your callback (redirect_uri) endpoint should receive the callback request as required and be able to retrieve a token from the token endpoint.\n\nIf you need to get a login for a specific user you can use the `OAuth2TokenCallback` interface to provide your own or set values in the `DefaultOAuth2TokenCallback`\n\n```kotlin\n@Test\nfun loginWithIdTokenForSubjectFoo() {\n    server.enqueueCallback(\n        DefaultOAuth2TokenCallback(\n            issuerId = issuerId,\n            subject = \"foo\"\n        )\n    )\n  // Invoke your app here and assert user foo is logged in\n}\n```\n\n If you need specific claims in the resulting `id_token` - e.g. `acr` or a custom claim you can also use the `OAuth2TokenCallback`:\n\n~~~kotlin\n@Test\nfun loginWithIdTokenForAcrClaimEqualsLevel4() {\n    server.enqueueCallback(\n        DefaultOAuth2TokenCallback(\n            issuerId = issuerId,\n            claims = mapOf(\"acr\" to \"Level4\")\n        )\n    )\n  // Invoke your app here and assert acr=Level4 is present in id_token\n}\n~~~\n\n\n##### Testing an API requiring access_token (e.g. a signed JWT)\n\n```kotlin\nval token: SignedJWT = oAuth2Server.issueToken(issuerId, \"someclientid\", DefaultOAuth2TokenCallback())\n//use your favourite HTTP client to invoke your API and attach the serialized token\nval request = // ....\nrequest.addHeader(\"Authorization\", \"Bearer ${token.serialize()}\")\n```\nIf you for some reason need to manipulate the system time/clock you can configure the OAuth2TokenProvider to use a specific time, resulting in the `iat` claim being set to that time:\n\n```kotlin\n@Test\nfun testWithSpecificTime() {\n    val server = MockOAuth2Server(\n        config = OAuth2Config(\n            tokenProvider = OAuth2TokenProvider(systemTime = Instant.parse(\"2020-01-21T00:00:00Z\")\n        )\n    )\n    val token = server.issueToken(issuerId = \"issuer1\")\n    // do whatever token testing you need to do here and assert the token has iat=2020-01-21T00:00:00Z\n}\n```\n\n##### More examples \n\nHave a look at some examples in both Java and Kotlin in the src/test directory:\n* [Kotlin with the ktor framework](src/test/kotlin/examples/kotlin/ktor)\n* [Java with Spring Boot and Spring Security](src/test/java/examples/java/springboot/)\n\n### API\n\n##### Server URLs\n\nYou can retrieve URLs from the server with the correct port and issuerId etc. by invoking one of the ` fun *Url(issuerId: String): HttpUrl` functions/methods: \n\n```kotlin\nval server = MockOAuth2Server()\nserver.start()\nval wellKnownUrl = server.wellKnownUrl(\"yourissuer\")\n// will result in the following url:\n// http://localhost:\u003ca random port\u003e/yourissuer/.well-known/openid-configuration\n```\n\n### Standalone server\n\nThe standalone server will default to port `8080` and can be started by invoking `main()` in  `StandaloneMockOAuth2Server.kt` (in kotlin) or `StandaloneMockOAuth2ServerKt` (in Java)\n\nOn Windows, it's easier to run the server in docker while specifying the host as localhost, e.g. `docker run -p 8080:8080 -h localhost $IMAGE_NAME`\n\n\u003e **Note**\n\u003e If you want to check if the server is up and running you can visit `/isalive` and see if you get a 200 in return.\n\n#### Configuration\n\nThe standalone server supports the following configuration by `ENV` variables:\n\n| Variable                | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |\n|-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `SERVER_HOSTNAME`       | Lets the standalone server bind to a specific hostname, by default it binds to `0.0.0.0`                                                                                                                                                                                                                                                                                                                                                                                               |\n| `SERVER_PORT` or `PORT` | The port that the standalone server will listen to, defaults to `8080`. The `PORT` environment variable may be used to [run the Docker image on Heroku](https://devcenter.heroku.com/articles/container-registry-and-runtime#pushing-an-existing-image) as per the documentation [here](https://devcenter.heroku.com/articles/setting-the-http-port-for-java-applications).                                                                                                            |\n| `JSON_CONFIG_PATH`      | The absolute path to a json file containing configuration about the OAuth2 part of the server (`OAuth2Config`). More details on the format below.                                                                                                                                                                                                                                                                                                                                      |\n| `JSON_CONFIG`           | The actual JSON content of `OAuth2Config`, this ENV var takes precedence over the `JSON_CONFIG_PATH` var. More details on the format below.                                                                                                                                                                                                                                                                                                                                            |\n| `LOG_LEVEL`             | How verbose the root logging output is, defaults to `INFO`                                                                                                                                                                                                                                                                                                                                                                                                                             |\n| `LOGBACK_CONFIG`        | You can override the default logging config in [logback-standalone.xml](src/main/resources/logback-standalone.xml) with a path to your own logback xml file.                                                                                                                                                                                                                                                                                                                           |\n\n##### JSON_CONFIG \n\nThe JSON_CONFIG lets you configure the contents of the [`OAuth2Config`](src/main/kotlin/no/nav/security/mock/oauth2/OAuth2Config.kt) class using JSON.\n\n\nExample:\n```json\n{\n    \"interactiveLogin\": true,\n    \"httpServer\": \"NettyWrapper\",\n    \"tokenCallbacks\": [\n        {\n            \"issuerId\": \"issuer1\",\n            \"tokenExpiry\": 120,\n            \"requestMappings\": [\n                {\n                    \"requestParam\": \"code\",\n                    \"match\": \"code1\",\n                    \"claims\": {\n                        \"sub\": \"subByCode\",\n                        \"aud\": [\n                            \"audByCode\"\n                        ]\n                    }\n                }\n            ]\n        },\n        {\n            \"issuerId\": \"issuer2\",\n            \"requestMappings\": [\n                {\n                    \"requestParam\": \"someparam\",\n                    \"match\": \"somevalue\",\n                    \"claims\": {\n                        \"sub\": \"subBySomeParam\",\n                        \"aud\": [\n                            \"audBySomeParam\"\n                        ]\n                    }\n                }\n            ]\n        }\n    ]\n}\n```\n\nA token provider can support different `signing` algorithms. Configure your token provider and\nadd this to your config with preferred `JWS algorithm`:\n\n```json\n{\n  \"tokenProvider\" : {\n    \"keyProvider\" : {\n      \"algorithm\" : \"ES256\"\n    }\n  }\n}\n```\n\nA token provider can also support a static \"systemTime\", i.e. the time for when the token is issued (`iat` claim) if you have tests that require a specific time.\nThe following configuration will set the system time to `2020-01-21T00:00:00Z`:\n\n```json\n{\n  \"tokenProvider\" : {\n    \"systemTime\" : \"2020-01-21T00:00:00Z\"\n  }\n}\n```\n\n| Property             | Description                                                                                                                                                                                                                                                                       |\n|----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `interactiveLogin`   | `true` or `false`, enables login screen when redirecting to server `/authorize` endpoint                                                                                                                                                                                          |\n| `loginPagePath`      | An optional string refering to a html file that is served as login page. This page needs to contain a form that posts a `username` and optionally a `claims` field. See `src/test/resource/login.example.html` as an example.                                                     |\n| `staticAssetsPath`   | The path to a directory containing static resources/assets. Lets you serve your own static resources from the server. Resources are served under the `/static` URL path. E.g. http://localhost:8080/static/myimage.svg or by reference `/static/myimage.svg` from the login page. |                                                     |\n| `rotateRefreshToken` | `true` or `false`, setting to true will generate a new unique refresh token when using the `refresh_token` grant.                                                                                                                                                                 | \n| `httpServer`         | A string identifying the httpserver to use. Must match one of the following enum values: `MockWebServerWrapper` or `NettyWrapper`                                                                                                                                                 |\n| `tokenCallbacks`     | A list of [`RequestMappingTokenCallback`](src/main/kotlin/no/nav/security/mock/oauth2/token/OAuth2TokenCallback.kt) that lets you specify which token claims to return when a token request matches the specified condition.                                                      |\n\n*From the first JSON example above:* \n\nA token request to `http://localhost:8080/issuer1/token` with parameter `code` equal to `code1` will match the first `tokenCallback`:\n\n```json\n{\n    \"issuerId\": \"issuer1\",\n    \"tokenExpiry\": 120,\n    \"requestMappings\": [\n        {\n            \"requestParam\": \"code\",\n            \"match\": \"code1\",\n            \"claims\": {\n                \"sub\": \"subByCode\",\n                \"aud\": [\n                    \"audByCode\"\n                ]\n            }\n        }\n    ]\n}\n```\n\nand return a token response containing a token with the following claims:\n\n```json\n{\n  \"sub\": \"subByCode\",\n  \"aud\": \"audByCode\",\n  \"nbf\": 1616416942,\n  \"iss\": \"http://localhost:54905/issuer1\",\n  \"exp\": 1616417062,\n  \"iat\": 1616416942,\n  \"jti\": \"28697333-6f25-4b1f-b2c2-409ce010933a\"\n}\n```\n\nEarlier versions of this documentation used `scope` as `requestParam` in the example. The scope request parameter is no logner supported by nimbus due to [c960757](https://github.com/navikt/mock-oauth2-server/commit/c9607571743cc087b190112f2197f4ac0a27aef2), so the call back needs to be configured with a different key.\n\nUse variable `clientId` to set `sub` claim for Client Credentials Grant dynamically.\n\nA token request with client credentials where `clientId = myClientId` and `tokenCallback`: \n```json\n{\n    \"issuerId\": \"issuer1\",\n    \"tokenExpiry\": 120,\n    \"requestMappings\": [\n        {\n            \"requestParam\": \"code\",\n            \"match\": \"code1\",\n            \"claims\": {\n                \"sub\": \"${clientId}\",\n                \"aud\": [\n                    \"audByCode\"\n                ]\n            }\n        }\n    ]\n}\n```\nwill return a token response containing a token with the following claims:\n\n\n```json\n{\n  \"sub\": \"myClientId\",\n  \"aud\": \"audByCode\",\n  \"nbf\": 1616416942,\n  \"iss\": \"http://localhost:54905/issuer1\",\n  \"exp\": 1616417062,\n  \"iat\": 1616416942,\n  \"jti\": \"28697333-6f25-4b1f-b2c2-409ce010933a\"\n}\n```\n\n#### Docker \n\nBuild to local docker daemon\n\n```gradle\n./gradlew -Djib.from.platforms=linux/amd64 jibDockerBuild # or alternatively -Djib.from.platforms=linux/arm64 for ARM64\n```\n\nRun container\n\n```gradle\ndocker run -p 8080:8080 $IMAGE_NAME\n```\n\n#### Docker-Compose\n\nIn order to get container-to-container networking to work smoothly alongside browser interaction you must specify a host entry in your `hosts` file, `127.0.0.1 host.docker.internal` and set `hostname` in the **mock-oauth2-server** service in your `docker-compose.yaml` file:\n\n```yaml\nversion: '3.7'\nservices:\n  your_app:\n    build: .\n    ports:\n      - 8080:8080\n  mock-oauth2-server:\n    image: ghcr.io/navikt/mock-oauth2-server:$MOCK_OAUTH2_SERVER_VERSION\n    ports:\n      - 8080:8080\n    hostname: host.docker.internal\n```\n\n#### Debugger\n\nThe debugger is a OAuth2 client implementing the `authorization_code` flow with a UI for debugging (e.g. request parameters).\nPoint your browser to [http://localhost:8080/default/debugger](http://localhost:8080/default/debugger) to check it out.\n\n### Enabling HTTPS\n\nIn order to enable HTTPS you can either provide your own keystore or let the server generate one for you.\n\n#### Unit tests\n\nYou need to supply the server with an SSL config, in order to do that you must specify your chosen server type in `OAuth2Config` and \npass in the SSL config to your server.\n\n*Generate keystore:*\n```kotlin\nval ssl = Ssl()\nval server = MockOAuth2Server(\n    OAuth2Config(httpServer = MockWebServerWrapper(ssl))\n)\n```\n*This will generate a SSL certificate for `localhost` and can be added to your client's truststore by getting the ssl config:\n`ssl.sslKeystore.keyStore`*\n\n*Bring your own:*\n```kotlin\nval ssl = Ssl(\n    SslKeystore(\n        keyPassword = \"\",\n        keystoreFile = File(\"src/test/resources/localhost.p12\"),\n        keystorePassword = \"\",\n        keystoreType = SslKeystore.KeyStoreType.PKCS12\n    )\n)\nval server = MockOAuth2Server(\n    OAuth2Config(httpServer = MockWebServerWrapper(ssl))\n)\n```\n\n#### Docker / Standalone mode - JSON_CONFIG\n\nIn order to enable HTTPS for the server in Docker or standalone mode\nyou can either make the server generate the keystore or bring your own.\n\n*Generate keystore:*\n\n```json\n{\n  \"httpServer\" : {\n    \"type\" : \"NettyWrapper\",\n    \"ssl\" : {}\n  }\n}\n```\n\n*Bring your own:*\n\n```json\n\n{\n    \"httpServer\" : {\n        \"type\" : \"NettyWrapper\",\n        \"ssl\" : {\n            \"keyPassword\" : \"\",\n            \"keystoreFile\" : \"src/test/resources/localhost.p12\",\n            \"keystoreType\" : \"PKCS12\",\n            \"keystorePassword\" : \"\" \n        }\n    }\n}\n```\n\n## Upgrading the gradle wrapper\nFind the newest version of gradle here: https://gradle.org/releases/\nThen run this command:\n```./gradlew wrapper --gradle-version $gradleVersion```\n\nRemeber to also update the gradle version in the build.gradle.kts file\n``` gradleVersion = \"$gradleVersion\"```\n\n\n## 👥 Contact\n\nThis project is currently maintained by the organisation [@navikt](https://github.com/navikt).\n\nIf you need to raise an issue or question about this library, please create an issue here and tag it with the appropriate label.\n\nFor contact requests within the [@navikt](https://github.com/navikt) org, you can use the Slack channel #pig_sikkerhet\n\nIf you need to contact anyone directly, please see contributors.\n\n## ✏️ Contributing\n\nTo get started, please fork the repo and checkout a new branch. You can then build the library with the Gradle wrapper\n\n```shell script\n./gradlew build\n```\n\nSee more info in [CONTRIBUTING.md](CONTRIBUTING.md)\n\n## ⚖️ License\nThis library is licensed under the [MIT License](LICENSE.md)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnavikt%2Fmock-oauth2-server","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnavikt%2Fmock-oauth2-server","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnavikt%2Fmock-oauth2-server/lists"}