Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
@octokit/oauth-app
Advanced tools
@octokit/oauth-app is a Node.js library that simplifies the process of implementing GitHub OAuth applications. It provides a set of tools to handle OAuth flows, manage tokens, and interact with GitHub's API securely.
OAuth App Initialization
This feature allows you to initialize an OAuth application with your GitHub client ID and client secret.
const { OAuthApp } = require('@octokit/oauth-app');
const app = new OAuthApp({
clientId: 'your-client-id',
clientSecret: 'your-client-secret'
});
Handling OAuth Web Flow
This feature allows you to handle the OAuth web flow, including exchanging the authorization code for an access token and using the token to authenticate API requests.
app.on('oauth', async ({ token, octokit }) => {
const { data: { login } } = await octokit.request('GET /user');
console.log('Authenticated as', login);
});
Token Management
This feature allows you to manage tokens, including creating, refreshing, and revoking tokens.
app.on('token', async ({ token }) => {
console.log('New token created:', token);
});
passport-github is a GitHub authentication strategy for Passport, a popular authentication middleware for Node.js. It provides a way to authenticate users using their GitHub accounts. Compared to @octokit/oauth-app, passport-github is more focused on user authentication and session management, while @octokit/oauth-app provides a more comprehensive set of tools for managing OAuth flows and interacting with GitHub's API.
simple-oauth2 is a library that provides a simple and consistent way to handle OAuth2 flows in Node.js applications. It supports various OAuth2 providers, including GitHub. Compared to @octokit/oauth-app, simple-oauth2 is more generic and can be used with multiple OAuth2 providers, while @octokit/oauth-app is specifically designed for GitHub OAuth applications.
node-oauth2-server is a complete, framework-agnostic implementation of the OAuth2 server specification for Node.js. It allows you to create your own OAuth2 server and manage tokens. Compared to @octokit/oauth-app, node-oauth2-server is more focused on providing a full OAuth2 server implementation, while @octokit/oauth-app is focused on client-side OAuth flows and interacting with GitHub's API.
GitHub OAuth toolset for Node.js
OAuthApp.defaults(options)
app.on(eventName, eventHandler)
app.octokit
app.getUserOctokit(options)
app.getWebFlowAuthorizationUrl(options)
app.createToken(options)
app.checkToken(options)
app.resetToken(options)
app.refreshToken(options)
app.scopeToken(options)
app.deleteToken(options)
app.deleteAuthorization(options)
Browsers |
|
---|---|
Node |
Install with |
[!IMPORTANT] As we use conditional exports, you will need to adapt your
tsconfig.json
by setting"moduleResolution": "node16", "module": "node16"
.See the TypeScript docs on package.json "exports".
See this helpful guide on transitioning to ESM from @sindresorhus
import { OAuthApp, createNodeMiddleware } from "@octokit/oauth-app";
import { createServer } from "node:http";
const app = new OAuthApp({
clientType: "oauth-app",
clientId: "1234567890abcdef1234",
clientSecret: "1234567890abcdef1234567890abcdef12345678",
});
app.on("token", async ({ token, octokit }) => {
const { data } = await octokit.request("GET /user");
console.log(`Token retrieved for ${data.login}`);
});
createServer(createNodeMiddleware(app)).listen(3000);
// can now receive user authorization callbacks at /api/github/oauth/callback
// See all endpoints at https://github.com/octokit/oauth-app.js#middlewares
GitHub Apps do not support scopes
. If the GitHub App has expiring user tokens enabled, the token used for the octokit
instance will be refreshed automatically, and the additional refresh-related properties will be passed to the "token"
event handler.
import { OAuthApp, createNodeMiddleware } from "@octokit/oauth-app";
import { createServer } from "node:http";
const app = new OAuthApp({
clientType: "github-app",
clientId: "lv1.1234567890abcdef",
clientSecret: "1234567890abcdef1234567890abcdef12345678",
});
app.on("token", async ({ token, octokit, expiresAt }) => {
const { data } = await octokit.request("GET /user");
console.log(`Token retrieved for ${data.login}`);
});
createServer(createNodeMiddleware(app)).listen(3000);
// can now receive user authorization callbacks at /api/github/oauth/callback
// See all endpoints at https://github.com/octokit/oauth-app.js#middlewares
public/
folder, hosted on Glitch: https://glitch.com/~github-oauth-clientOAuthApp.defaults(options)
Create a new OAuthApp
with custom defaults for the constructor options
const MyOAuthApp = OAuthApp.defaults({
Octokit: MyOctokit,
});
const app = new MyOAuthApp({ clientId, clientSecret });
// app.octokit is now an instance of MyOctokit
name | type | description |
---|---|---|
clientId
|
number
| Required. Find Client ID on the app’s about page in settings. |
clientSecret
|
number
| Required. Find Client Secret on the app’s about page in settings. |
clientType
|
string
|
Either "oauth-app" or "github-app" . Defaults to "oauth-app" .
|
allowSignup
|
boolean
|
Sets the default value for app.getWebFlowAuthorizationUrl(options) .
|
redirectUrl
|
string
| The URL in your application where users will be sent after authorization. See Redirect URLs in GitHub’s Developer Guide. |
defaultScopes
|
Array of strings
|
Only relevant when Sets the default |
log
|
object
|
Used for internal logging. Defaults to console .
|
Octokit
|
Constructor
|
You can pass in your own Octokit constructor with custom defaults and plugins. The Octokit Constructor must use an authentication strategy that is compatible with`@octokit/auth-oauth-app. For usage with enterprise, set
Defaults to |
app.on(eventName, eventHandler)
Called whenever a new OAuth access token is created for a user. It accepts two parameters, an event name and a function with one argument
app.on("token.created", async (context) => {
const { data } = await context.octokit.request("GET /user");
app.log.info(`New token created for ${data.login}`);
});
The eventName
can be one of (or an array of)
token.created
token.reset
token.refreshed
(GitHub Apps only)token.scoped
(GitHub Apps only)token.deleted
authorization.deleted
All event handlers are awaited before continuing.
context
can have the following properties
property | type | description |
---|---|---|
context.name
|
string
|
Name of the event. One of: token , authorization
|
context.action
|
string
|
Action of the event. One of: created , reset , deleted
|
context.authentication
|
object
|
The OAuth authentication object. See https://github.com/octokit/auth-oauth-user.js/#authentication-object |
context.octokit
|
Octokit instance
|
Authenticated instance using the The |
app.octokit
Octokit instance with OAuth App authentication. Uses Octokit
constructor option
app.getUserOctokit(options)
const octokit = await app.getUserOctokit({ code: "code123" });
options
are the same as in app.createToken(options)
The octokit
instance is authorized using the user access token if the app is an OAuth app and a user-to-server token if the app is a GitHub app. If the token expires it will be refreshed automatically.
app.getWebFlowAuthorizationUrl(options)
Returns and object with all options and a url
property which is the authorization URL. See https://github.com/octokit/oauth-methods.js/#getwebflowauthorizationurl
const { url } = app.getWebFlowAuthorizationUrl({
state: "state123",
scopes: ["repo"],
});
name | type | description |
---|---|---|
redirectUrl
|
string
| The URL in your application where users will be sent after authorization. See Redirect URLs in GitHub’s Developer Guide. |
login
|
string
| Suggests a specific account to use for signing in and authorizing the app. |
scopes
|
array of strings
| An array of scope names (or: space-delimited list of scopes). If not provided, scope defaults to an empty list for users that have not authorized any scopes for the application. For users who have authorized scopes for the application, the user won't be shown the OAuth authorization page with the list of scopes. Instead, this step of the flow will automatically complete with the set of scopes the user has authorized for the application. For example, if a user has already performed the web flow twice and has authorized one token with user scope and another token with repo scope, a third web flow that does not provide a scope will receive a token with user and repo scope. |
state
|
string
|
An unguessable random string. It is used to protect against cross-site request forgery attacks.
Defaults to Math.random().toString(36).substr(2) .
|
allowSignup
|
boolean
|
Whether or not unauthenticated users will be offered an option to sign up for GitHub during the OAuth flow. The default is true . Use false in the case that a policy prohibits signups.
|
app.createToken(options)
The method can be used for both, the OAuth Web Flow and the OAuth Device Flow.
For the web flow, you have to pass the code
from URL redirect described in step 2.
const { token } = await app.createToken({
code: "code123",
});
name | type | description |
---|---|---|
code
|
string
|
Required. Pass the code that was passed as ?code query parameter in the authorization redirect URL.
|
state
|
string
|
Required. Pass the state that was passed as ?state query parameter in the authorization redirect URL.
|
Resolves with an user authentication object
For the device flow, you have to pass a onVerification
callback function, which prompts the user to enter the received user code at the received authorization URL.
name | type | description |
---|---|---|
onVerification
|
function
|
Required. A function that is called once the device and user codes were retrieved The
|
scopes
|
array of strings
|
Only relevant if Array of OAuth scope names that the user access token should be granted. Defaults to no scopes ( |
Resolves with an user authentication object
app.checkToken(options)
try {
const { created_at, app, user } = await app.checkToken({ token });
console.log(
`token valid, created on %s by %s for %s`,
created_at,
user.login,
app.name,
);
} catch (error) {
// token invalid or request error
}
name | type | description |
---|---|---|
token
|
string
| Required. |
Resolves with response body from "Check a token" request with an additional authentication
property which is a user authentication object.
app.resetToken(options)
const { data, authentication } = await app.resetToken({
token: "token123",
});
// "token123" is no longer valid. Use `token` instead
name | type | description |
---|---|---|
token
|
string
| Required. |
Resolves with response body from "Reset a token" request with an additional authentication
property which is a user authentication object.
app.refreshToken(options)
Expiring tokens are only supported by GitHub Apps, and only if expiring user tokens are enabled.
const { data, authentication } = await app.refreshToken({
refreshToken: "refreshtoken123",
});
name | type | description |
---|---|---|
refreshToken
|
string
| Required. |
Resolves with response body from "Renewing a user token with a refresh token" request (JSON) with an additional authentication
property which is a user authentication object.
app.scopeToken(options)
Scoping a token is only supported by GitHub Apps. "Scoping" in this context means to limit access to a selected installation, with a subset of repositories and permissions.
const { data, authentication } = await app.scopeToken({
clientType: "github-app",
clientId: "lv1.1234567890abcdef",
clientSecret: "1234567890abcdef12347890abcdef12345678",
token: "usertoken123",
target: "octokit",
repositories: ["oauth-app.js"],
permissions: {
issues: "write",
},
});
Options
name | type | description |
---|---|---|
target
|
string
|
Required unless targetId is set. The name of the user or organization to scope the user-to-server access token to.
|
targetId
|
integer
|
Required unless target is set. The ID of the user or organization to scope the user-to-server access token to.
|
repositories
|
array of strings
|
The list of repository names to scope the user-to-server access token to. repositories may not be specified if repository_ids is specified.
|
repository_ids
|
array of integers
|
The list of repository IDs to scope the user-to-server access token to. repositories may not be specified if repositories is specified.
|
permissions
|
object
| The permissions granted to the user-to-server access token. See GitHub App Permissions. |
Resolves with response body from "Create a scoped access token" request with an additional authentication
property which is a user authentication object.
app.deleteToken(options)
await app.deleteToken({
token: "token123",
});
// "token123" is no longer valid.
name | type | description |
---|---|---|
token
|
string
| Required. |
Resolves with response body from "Delete a token" request.
app.deleteAuthorization(options)
await app.deleteAuthorization({
token: "token123",
});
// "token123" is no longer valid, and no tokens can be created until the app gets re-authorized.
name | type | description |
---|---|---|
token
|
string
| Required. |
Resolves with response body from "Delete an app authorization" request.
A middleware is a method or set of methods to handle requests for common environments.
By default, all middlewares expose the following routes
Route | Route Description |
---|---|
GET /api/github/oauth/login | Redirects to GitHub's authorization endpoint. Accepts optional ?state and ?scopes query parameters. ?scopes is a comma-separated list of supported OAuth scope names |
GET /api/github/oauth/callback | The client's redirect endpoint. This is where the token event gets triggered |
POST /api/github/oauth/token | Exchange an authorization code for an OAuth Access token. If successful, the token event gets triggered. |
GET /api/github/oauth/token | Check if token is valid. Must authenticate using token in Authorization header. Uses GitHub's POST /applications/{client_id}/token endpoint |
PATCH /api/github/oauth/token | Resets a token (invalidates current one, returns new token). Must authenticate using token in Authorization header. Uses GitHub's PATCH /applications/{client_id}/token endpoint. |
PATCH /api/github/oauth/refresh-token | Refreshes an expiring token (invalidates current one, returns new access token and refresh token). Must authenticate using token in Authorization header. Uses GitHub's POST https://github.com/login/oauth/access_token OAuth endpoint. |
POST /api/github/oauth/token/scoped | Creates a scoped token (does not invalidate the current one). Must authenticate using token in Authorization header. Uses GitHub's POST /applications/{client_id}/token/scoped endpoint. |
DELETE /api/github/oauth/token | Invalidates current token, basically the equivalent of a logout. Must authenticate using token in Authorization header. |
DELETE /api/github/oauth/grant | Revokes the user's grant, basically the equivalent of an uninstall. must authenticate using token in Authorization header. |
createNodeMiddleware(app, options)
Native http server middleware for Node.js
import { OAuthApp, createNodeMiddleware } from "@octokit/oauth-app";
import { createServer } from "node:http";
const app = new OAuthApp({
clientType: "oauth-app",
clientId: "1234567890abcdef1234",
clientSecret: "1234567890abcdef1234567890abcdef12345678",
});
const middleware = createNodeMiddleware(app, {
pathPrefix: "/api/github/oauth",
});
createServer(middleware).listen(3000);
// can now receive user authorization callbacks at /api/github/oauth/callback
name | type | description |
---|---|---|
app
|
OAuthApp instance
| Required. |
options.pathPrefix
|
string
|
All exposed paths will be prefixed with the provided prefix. Defaults to |
createWebWorkerHandler(app, options)
Event handler for web worker environments (Cloudflare workers or Deno).
// worker.js
import { OAuthApp, createWebWorkerHandler } from "@octokit/oauth-app";
const app = new OAuthApp({
clientType: "oauth-app",
clientId: "1234567890abcdef1234",
clientSecret: "1234567890abcdef1234567890abcdef12345678",
});
const handleRequest = createWebWorkerHandler(app, {
pathPrefix: "/api/github/oauth",
});
addEventListener("fetch", (event) => {
event.respondWith(handleRequest(event.request));
});
// can now receive user authorization callbacks at /api/github/oauth/callback
name | type | description |
---|---|---|
app
|
OAuthApp instance
| Required. |
options.pathPrefix
|
string
|
All exposed paths will be prefixed with the provided prefix. Defaults to |
createAWSLambdaAPIGatewayV2Handler(app, options)
Event handler for AWS Lambda using API Gateway V2 HTTP integration.
// worker.js
import {
OAuthApp,
createAWSLambdaAPIGatewayV2Handler,
} from "@octokit/oauth-app";
const app = new OAuthApp({
clientType: "oauth-app",
clientId: "1234567890abcdef1234",
clientSecret: "1234567890abcdef1234567890abcdef12345678",
});
export const handler = createAWSLambdaAPIGatewayV2Handler(app, {
pathPrefix: "/api/github/oauth",
});
// can now receive user authorization callbacks at /api/github/oauth/callback
name | type | description |
---|---|---|
app
|
OAuthApp instance
| Required. |
options.pathPrefix
|
string
|
All exposed paths will be prefixed with the provided prefix. Defaults to |
When above middlewares do not meet your needs, you can build your own
using the exported handleRequest
function.
handleRequest
function is an abstract HTTP handler which accepts an OctokitRequest
and returns an OctokitResponse
if the request matches any predefined route.
Different environments (e.g., Node.js, Cloudflare Workers, Deno, etc.) exposes different APIs when processing HTTP requests (e.g.,
IncomingMessage
for Node.js,Request
for Cloudflare workers, etc.). Two HTTP-related types (OctokitRequest
andOctokitResponse
) are generalized to make an abstract HTTP handler possible.
To share the behavior and capability with the existing Node.js middleware (and be compatible with OAuth user authentication strategy in the browser), it is better to implement your HTTP handler/middleware based on handleRequest
function.
handleRequest
function takes three parameters:
name | type | description |
---|---|---|
app
|
OAuthApp instance
| Required. |
options.pathPrefix
|
string
|
All exposed paths will be prefixed with the provided prefix. Defaults to |
request
|
OctokitRequest
| Generalized HTTP request in `OctokitRequest` type. |
Implementing an HTTP handler/middleware for a certain environment involves three steps:
IncomingMessage
in Node.js) into an OctokitRequest
object. See node/parse-request.ts
for reference.OctokitResponse
object (e.g., as ServerResponse
in Node.js). See node/send-response.ts
for reference.OctokitRequest
object using handleRequest
.OctokitResponse
object using (2).See CONTRIBUTING.md
FAQs
GitHub OAuth toolset for Node.js
The npm package @octokit/oauth-app receives a total of 503,689 weekly downloads. As such, @octokit/oauth-app popularity was classified as popular.
We found that @octokit/oauth-app demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 4 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.