GitHub OAuth Device authentication strategy for JavaScript
@octokit/auth-oauth-device is implementing one of GitHub’s OAuth Device Flow.
- Usage
createOAuthDeviceAuth(options)auth(options)- Authentication object
auth.hook(request, route, parameters)orauth.hook(request, options)- Types
- How it works
- Contributing
- License
|
Browsers |
Load <script type="module">
import { createOAuthDeviceAuth } from "https://esm.sh/@octokit/auth-oauth-device";
</script> |
|---|---|
|
Node |
Install with import { createOAuthDeviceAuth } from "@octokit/auth-oauth-device"; |
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
const auth = createOAuthDeviceAuth({
clientType: "oauth-app",
clientId: "1234567890abcdef1234",
scopes: ["public_repo"],
onVerification(verification) {
// verification example
// {
// device_code: "3584d83530557fdd1f46af8289938c8ef79f9dc5",
// user_code: "WDJB-MJHT",
// verification_uri: "https://github.com/login/device",
// expires_in: 900,
// interval: 5,
// };
console.log("Open %s", verification.verification_uri);
console.log("Enter code: %s", verification.user_code);
},
});
const tokenAuthentication = await auth({
type: "oauth",
});
// resolves with
// {
// type: "token",
// tokenType: "oauth",
// clientType: "oauth-app",
// clientId: "1234567890abcdef1234",
// token: "...", /* the created oauth token */
// scopes: [] /* depend on request scopes by OAuth app */
// }GitHub Apps do not support scopes. Client IDs of GitHub Apps have a lv1. prefix. If the GitHub App has expiring user tokens enabled, the resulting authentication object has extra properties related to expiration and refreshing the token.
const auth = createOAuthDeviceAuth({
clientType: "github-app",
clientId: "lv1.1234567890abcdef",
onVerification(verification) {
// verification example
// {
// device_code: "3584d83530557fdd1f46af8289938c8ef79f9dc5",
// user_code: "WDJB-MJHT",
// verification_uri: "https://github.com/login/device",
// expires_in: 900,
// interval: 5,
// };
console.log("Open %s", verification.verification_uri);
console.log("Enter code: %s", verification.user_code);
},
});
const tokenAuthentication = await auth({
type: "oauth",
});
// resolves with
// {
// type: "token",
// tokenType: "oauth",
// clientType: "github-app",
// clientId: "lv1.1234567890abcdef",
// token: "...", /* the created oauth token */
// }
// or if expiring user tokens are enabled
// {
// type: "token",
// tokenType: "oauth",
// clientType: "github-app",
// clientId: "lv1.1234567890abcdef",
// token: "...", /* the created oauth token */
// refreshToken: "...",
// expiresAt: "2022-01-01T08:00:0.000Z",
// refreshTokenExpiresAt: "2021-07-01T00:00:0.000Z",
// }The createOAuthDeviceAuth method accepts a single options parameter
| name | type | description |
|---|---|---|
clientId
|
string
|
Required. Find your OAuth app’s Client ID in your account’s developer settings.
|
onVerification
|
function
|
Required. A function that is called once the device and user codes were retrieved
The const auth = createOAuthDeviceAuth({
clientId: "1234567890abcdef1234",
onVerification(verification) {
console.log("Open %s", verification.verification_uri);
console.log("Enter code: %s", verification.user_code);
await prompt("press enter when you are ready to continue");
},
}); |
clientType
|
string
|
Must be either |
request
|
function
|
You can pass in your own @octokit/request instance. For usage with enterprise, set baseUrl to the API root endpoint. Example:
import { request } from "@octokit/request";
createOAuthDeviceAuth({
clientId: "1234567890abcdef1234",
clientSecret: "secret",
request: request.defaults({
baseUrl: "https://ghe.my-company.com/api/v3",
}),
}); |
scopes
|
array of strings
|
Only relevant if Array of scope names enabled for the token. Defaults to |
The async auth() method returned by createOAuthDeviceAuth(options) accepts the following options
| name | type | description |
|---|---|---|
type
|
string
|
Required. Must be set to "oauth"
|
scopes
|
array of strings
|
Only relevant if the Array of scope names enabled for the token. Defaults to what was set in the strategy options. See available scopes |
refresh
|
boolean
|
Defaults to |
The async auth(options) method resolves to one of three possible objects
- OAuth APP user authentication
- GitHub APP user authentication with expiring tokens disabled
- GitHub APP user authentication with expiring tokens enabled
The differences are
scopesis only present for OAuth AppsrefreshToken,expiresAt,refreshTokenExpiresAtare only present for GitHub Apps, and only if token expiration is enabled
| name | type | description |
|---|---|---|
type
|
string
|
"token"
|
tokenType
|
string
|
"oauth"
|
clientType
|
string
|
"github-app"
|
clientId
|
string
|
The app's Client ID
|
token
|
string
|
The personal access token |
scopes
|
array of strings
|
array of scope names enabled for the token |
| name | type | description |
|---|---|---|
type
|
string
|
"token"
|
tokenType
|
string
|
"oauth"
|
clientType
|
string
|
"github-app"
|
clientId
|
string
|
The app's Client ID
|
token
|
string
|
The personal access token |
| name | type | description |
|---|---|---|
type
|
string
|
"token"
|
tokenType
|
string
|
"oauth"
|
clientType
|
string
|
"github-app"
|
clientId
|
string
|
The app's Client ID
|
token
|
string
|
The user access token |
refreshToken
|
string
|
The refresh token |
expiresAt
|
string
|
Date timestamp in ISO 8601 standard. Example: 2022-01-01T08:00:0.000Z
|
refreshTokenExpiresAt
|
string
|
Date timestamp in ISO 8601 standard. Example: 2021-07-01T00:00:0.000Z
|
auth.hook() hooks directly into the request life cycle. It amends the request to authenticate correctly based on the request URL.
The request option is an instance of @octokit/request. The route/options parameters are the same as for the request() method.
auth.hook() can be called directly to send an authenticated request
const { data: user } = await auth.hook(request, "GET /user");Or it can be passed as option to request().
const requestWithAuth = request.defaults({
request: {
hook: auth.hook,
},
});
const { data: user } = await requestWithAuth("GET /user");import {
OAuthAppStrategyOptions,
OAuthAppAuthOptions,
OAuthAppAuthentication,
GitHubAppStrategyOptions,
GitHubAppAuthOptions,
GitHubAppAuthentication,
GitHubAppAuthenticationWithExpiration,
} from "@octokit/auth-oauth-device";GitHub's OAuth Device flow is different from the web flow in two ways
- It does not require a URL redirect, which makes it great for devices and CLI apps
- It does not require the OAuth client secret, which means there is no user-owned server component required.
The flow has 3 parts (see GitHub documentation)
@octokit/auth-oauth-devicerequests a device and user code- Then the user has to open https://github.com/login/device (or it's GitHub Enterprise Server equivalent) and enter the user code
- While the user enters the code,
@octokit/auth-oauth-deviceis sending requests in the background to retrieve the OAuth access token. Once the user completed step 2, the request will succeed and the token will be returned
See CONTRIBUTING.md