OAuth user authentication without exposing client secret
Table of contents
auth-oauth-user-client.js requires a backend service to function.
@octokit/oauth-app provides
compatible Node.js/Express.js/Cloudflare Worker middlewares to support
auth-oauth-user-client.js.
|
Browsers |
Load <script type="module">
import { createOAuthUserClientAuth } from "https://cdn.skypack.dev/@octokit/auth-oauth-user-client";
</script> |
|---|---|
|
Node |
Install with const {
createOAuthUserClientAuth,
} = require("@octokit/auth-oauth-user-client"); |
const auth = createOAuthUserClientAuth({
clientId: "clientId123",
clientType: "github-app", // defaults to `"oauth-app"`
expirationEnabled: true, // defaults to `true` for GitHub App, `false` for OAuth App
});
// Get token from local session. Returns `null` when `code` or `state` search
// parameters is missing and no session can be fetched from [`localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage).
const session = await auth({ type: "getToken" });
// Use `signIn` command to redirect to GitHub when the user is not signed in.
if (!session) await auth({ type: "signIn" });
// `token` can be retrieved from a non-null `session`.
else console.log(session.authentication.token);|
Browsers |
Load <script type="module">
import { Octokit } from "https://cdn.skypack.dev/@octokit/core";
import { createOAuthUserClientAuth } from "https://cdn.skypack.dev/@octokit/auth-oauth-user-client";
</script> |
|---|---|
|
Node |
Install with const { Octokit } = require("@octokit/core");
const {
createOAuthUserClientAuth,
} = require("@octokit/auth-oauth-user-client"); |
const octokit = new Octokit({
authStrategy: createOAuthUserClientAuth,
auth: {
clientId: "clientId123",
clientType: "github-app", // defaults to `"oauth-app"`
expirationEnabled: true, // defaults to `true` for GitHub App, `false` for OAuth App
},
});
const session = await octokit.auth();
// Use `signIn` command to redirect to GitHub when the user is not signed in.
if (!session) await octokit.auth({ type: "signIn" });
// Make GitHub API requests.
else {
const { data } = await octokit.request("GET /user");
console.log(data);
}The createOAuthUserClientAuth method accepts a single options object as argument:
| name | type | description |
|---|---|---|
clientId |
string |
Required. Find Client ID on the app’s about page in settings. |
clientType |
string |
Either "oauth-app" or "github-app". Defaults to "oauth-app". |
expirationEnabled |
boolean |
Defaults to true for GitHub App, false for OAuth App. |
session |
object |
Initial session, defaults to null. See session object. |
defaultScopes |
string |
Only relevant for OAuth App. See available scopes. |
serviceOrigin |
string |
Defaults to location.origin. Required only when the @octokit/oauth-app Node.js/Express.js/Cloudflare middleware is deployed at a different origin. |
servicePathPrefix |
string |
Defaults to "/api/github/oauth". Required only when the @octokit/oauth-app Node.js/Express.js/Cloudflare middleware is created with custom pathPrefix. |
sessionStore |
object or false |
Custom store to get/set session object, false to disable session persistence. See custom store. |
stateStore |
object or false |
Custom store to get/set state string, false to disable state persistence. |
request |
function |
You can pass in your own @octokit/request instance. For usage with enterprise, set baseUrl to the API root endpoint. See custom request |
By default, auth-oauth-user-client.js uses localStorage to store JSON
serialized session object and state string.
Pass sessionStore or stateStore in createOAuthUserClientAuth(options) (or
new Octokit({auth})) to use your custom code to persist session or state.
For example:
const sessionStore = {
get: async() => { /* return local session or `null` when there is no session */ }
set: async(session) => {
if (session == null) { /* delete local session */ }
else { /* create or update local session */ }
}
}
const auth = createOAuthUserClientAuth({
clientId: "clientId123",
sessionStore
});const { request } = require("@octokit/request");
createOAuthAppAuth({
clientId: "1234567890abcdef1234",
request: request.defaults({
baseUrl: "https://ghe.my-company.com/api/v3",
}),
});The async auth() method returned by createOAuthUserClientAuth(options) accepts the following commands:
| Command | {type: } |
Optional Arguments |
|---|---|---|
| Sign in | "signIn" |
|
| Get (local) token | "getToken" |
– |
| Create an app token | "createToken" |
– |
| Check a token | "checkToken" |
– |
| Create a scoped access token (for OAuth App) | "createScopedToken" |
– |
| Reset a token | "resetToken" |
– |
| Renewing a user token with a refresh token (for GitHub App with token expiration enabled) | "refreshToken" |
– |
| Delete an app token (sign out) | "deleteToken" |
offline: true (only deletes session from local session store) |
| Delete an app authorization | "deleteAuthorization" |
– |
The async auth(options) method resolves to an object with the following properties:
| property | type | description |
|---|---|---|
authentication |
object |
See authentication object |
There are three possible types of authentication object:
- OAuth APP authentication token
- GitHub APP user authentication token with expiring disabled
- GitHub APP user authentication token with expiring 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 |
"oauth-app" |
clientId |
string |
The clientId from the strategy options |
token |
string |
The user 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 clientId from the strategy options |
token |
string |
The user access token |
| name | type | description |
|---|---|---|
type |
string |
"token" |
tokenType |
string |
"oauth" |
clientType |
string |
"github-app" |
clientId |
string |
The clientId from the strategy options |
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: 2022-01-01T08: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");See CONTRIBUTING.md