Skip to main content

Test OAuth 2.0 with a Mock Server

If you've ever tried to test "Sign in with Google" or "Sign in with GitHub" during early development, you know the drill: register your app, wait for verification, enter redirect URLs, copy-paste client secrets, and inevitably hit a rate limit somewhere. And all you wanted was to check if the button works and see if your callback function is firing. It gets tiring fast.

This is where Beeceptor’s mock OAuth 2.0 server comes in handy. It gives you a fully functional, no-setup-required OAuth provider that simulates the core steps of login flows. You don’t need client secrets. You don’t even need valid credentials. The mock server accepts any input and gives you back a realistic access token and user profile. It's fast, flexible, and perfect for local testing or CI pipelines.

Let me walk you through how to use it, especially in combination with auth.js, a popular authentication library for Next.js and other Node-based frameworks.

Getting Started

Beeceptor hosts a public OAuth mock server at:

https://oauth-mock.mock.beeceptor.com

This server supports all the endpoints you'd expect from a real provider: /authorize, /token, and /userinfo. The neat part? These endpoints are provider-specific, you get one set for Google and another for GitHub. Internally, they behave just like the real ones would, returning fake tokens and user data in formats compatible with most OAuth clients.

  • GET /oauth/authorize – Serves a login page (accepts any email/password)
  • POST /oauth/token/google – Returns a mock access token (Google)
  • POST /oauth/token/github – Returns a mock access token (GitHub)
  • GET /userinfo/google – Returns mock Google user info
  • GET /userinfo/github – Returns mock GitHub user info

You don’t even need to preconfigure anything on Beeceptor’s dashboard to start using these. They just work. Hit the /authorize URL, and you'll see a login form. Type any email and password, hit submit, and the server will continue the flow. That’s it.

Integrating with auth.js

Let’s assume you already have a basic auth.js setup in your Next.js app. If not, it’s easy to scaffold one using their quick start guide. Once that's done, your goal is to replace the actual Google or GitHub provider config with the mock equivalents.

Here's where it gets fun. In your authOptions, you’ll define the mock providers using custom endpoint overrides. You’ll set the authorization URL to point to Beeceptor’s /authorize, the token URL to /token/github or /token/google, and the userinfo URL to /userinfo/github or /userinfo/google. You can hardcode dummy client IDs and secrets because Beeceptor’s mock server doesn’t verify them.

Once you’ve plugged those in, your login buttons will still say “Sign in with Google” or “Sign in with GitHub”, but they’ll route everything through the mock server.

Here's a simplified view of what your provider config might look like:

Google({
clientId: "google-id-123", // IMPORTANT, use this value for the mock setup!
clientSecret: "dummy-google-secret",
authorization: {
url: "https://oauth-mock.mock.beeceptor.com/oauth/authorize",
},
token: {
url: "https://oauth-mock.mock.beeceptor.com/oauth/token/google",
},
userinfo: {
url: "https://oauth-mock.mock.beeceptor.com/userinfo/google",
},
profile(profile) {
return {
id: String(profile.sub),
name: profile.name,
email: profile.email,
image: profile.picture,
}
},
})

The Google() function is a provider helper imported from the @auth/core/providers/google module. It is part of the auth.js ecosystem (formerly next-auth).

Similarly, you can set up the GitHub provider:

GitHub({
clientId: "dummy-github-id",
clientSecret: "dummy-github-secret",
authorization: {
url: "https://oauth-mock.mock.beeceptor.com/oauth/authorize"
},
token: {
url: "https://oauth-mock.mock.beeceptor.com/oauth/token/github",
},
userinfo: {
url: "https://oauth-mock.mock.beeceptor.com/userinfo/github",
},
profile(profile) {
return {
id: String(profile.id),
name: profile.name || profile.login,
email: profile.email,
image: profile.avatar_url,
}
},
})

Simulating OAuth Login with Beeceptor

Here is a step wise flow:

Step-1: Click the Login Button

Start by triggering a login from your frontend. For example, if you're using auth.js, navigate to the default /api/auth/signin route. You’ll see a list of configured providers. Click “Sign in with Google” or “Sign in with GitHub”.

Behind the scenes, this will redirect your browser to Beeceptor’s mock /oauth/authorize endpoint.

Step-2: Fill the Mock Login Form

You’ll now see a minimal login form served by Beeceptor. It has just two fields: email and password. The form is designed to mimic a real provider’s login page, but the key difference is: it accepts anything.

Type any email you e.g. tester@fake.com works fine. Add any password e.g. letmein123, password, or even gibberish. There’s no validation or real authentication here.

Hit the “Sign In” button to submit the form.

Step-3: Get Redirected with Authorization Code

After submitting, Beeceptor simulates the provider's redirect flow. It sends you back to your application (to the redirect URI specified by auth.js) along with a query parameter, an authorization code.

This looks just like what you'd get from Google or GitHub. No special handling is needed on your end. auth.js picks it up and proceeds with the next step automatically.

Step-4: Exchange the Code for an Access Token

Now your app sends a backend request to Beeceptor’s /oauth/token/google or /oauth/token/github endpoint, depending on the provider you clicked. This is handled internally by auth.js, you don't have to write this part yourself.

Beeceptor responds with a mock token payload. This usually includes an access_token, a token_type, expires_in, and optionally an id_token. The format closely resembles what real OAuth providers return.

Step-5: Fetch the User’s Profile

Next, auth.js uses the access token to make a request to /userinfo/google or /userinfo/github. This request also happens automatically as part of the built-in provider behavior.

Beeceptor returns a realistic user profile. For Google, you’ll get fields like:

{
"sub": "110248495921238986420",
"email": "oauth-sample-google@beeceptor.com",
"name": "Bee User",
"picture": "https://cdn.beeceptor.com/assets/images/logo-beeceptor.png",
// ... other fields
}

For GitHub, it will look like this:

{
"id": 459,
"login": "bee-user",
"email": "oauth-sample-github@beeceptor.com",
"name": "Bee User",
"avatar_url": "https://cdn.beeceptor.com/assets/images/logo-beeceptor.png"
// ... other fields
}

Step-6: Session is Created, User is Logged In

Once the profile data is received, auth.js uses it to populate the user session. If you're using JWT-based sessions (which is default), the token is stored client-side.

Your frontend now has access to session.user.name, session.user.email, and other profile fields. If you check your browser dev tools or inspect the session, you’ll see that the login was successful.

Your UI should now reflect the authenticated state showing a welcome message, user avatar, or a “Sign out” link depending on how you've configured your components.

Control Flow

The entire flow can be summarized in a sequence diagram:

For more details and to explore the mock server, visit Beeceptor’s OAuth 2.0 Mock Server.


Useful Links