Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG]: Module @octokit/auth-token declares Token locally, but it is not exported. #398

Closed
1 task done
NatoBoram opened this issue Mar 28, 2024 · 8 comments · Fixed by #404 · May be fixed by #400
Closed
1 task done

[BUG]: Module @octokit/auth-token declares Token locally, but it is not exported. #398

NatoBoram opened this issue Mar 28, 2024 · 8 comments · Fixed by #404 · May be fixed by #400
Labels
Type: Bug Something isn't working as documented

Comments

@NatoBoram
Copy link

What happened?

Previously, I was using this type:

import type { Token } from "@octokit/auth-token/dist-types/types.js"

With the conversion to ESModules (I think), the file is no longer accessible, so I have to do with this:

// Module '"@octokit/auth-token"' declares 'Token' locally, but it is not exported. ts(2459)
import type { Token } from "@octokit/auth-token"

But the type forgot to be exported

Versions

"@octokit/auth-token": "^5.0.1",

Relevant log output

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct
@NatoBoram NatoBoram added Status: Triage This is being looked at and prioritized Type: Bug Something isn't working as documented labels Mar 28, 2024
Copy link

👋 Hi! Thank you for this contribution! Just to let you know, our GitHub SDK team does a round of issue and PR reviews twice a week, every Monday and Friday! We have a process in place for prioritizing and responding to your input. Because you are a part of this community please feel free to comment, add to, or pick up any issues/PRs that are labled with Status: Up for grabs. You & others like you are the reason all of this works! So thank you & happy coding! 🚀

@gr2m
Copy link
Contributor

gr2m commented Mar 28, 2024

import type { Token } from "@octokit/auth-token/dist-types/types.js"

That is considered using internal APIs. I wouldn't do this in general, it could break at any moment, there are no guarantees.

// Module '"@octokit/auth-token"' declares 'Token' locally, but it is not exported. ts(2459)
import type { Token } from "@octokit/auth-token"

As mentioned in your pull request, Token is just an alias for string. We could probably remove it altogether.

@NatoBoram
Copy link
Author

NatoBoram commented Mar 29, 2024

I see it as valuable documentation. It shows where it comes from when I'm using it in code. In a flow where I have multiple authentication strategies depending on the deployment state (local testing vs deployed to prod), this gives clarity over what it is when I use auth: StrategyOptions | Token rather than auth: StrategyOptions | string.

It could also be used to expose JSDocs with information about what the token is and links to the documentation. A type template could be used to clarify its format, like type Token = 'gh_${string}' if this format is commonly used. Not that it's there, but just having the type alias itself is good documentation.

@wolfy1339
Copy link
Member

I agree that having JSDoc is a useful tool.

I really like the idea of the type format. You could narrow down the different token types with the different formats

@NatoBoram
Copy link
Author

I got something working with formats:

 src/create-token-auth.ts | 11 ++++++++---
 src/types.ts             | 23 +++++++++++++++++++++--
 test/index.test.ts       |  2 ++
 3 files changed, 31 insertions(+), 5 deletions(-)

diff --git a/src/create-token-auth.ts b/src/create-token-auth.ts
index 052c8df..4fac750 100644
--- a/src/create-token-auth.ts
+++ b/src/create-token-auth.ts
@@ -1,9 +1,9 @@
 import { auth } from "./auth.js";
 import { hook } from "./hook.js";
-import type { StrategyInterface, Token } from "./types.js";
+import type { BearerToken, StrategyInterface, Token } from "./types.js";
 
 export const createTokenAuth: StrategyInterface = function createTokenAuth(
-  token: Token,
+  token: Token | BearerToken,
 ) {
   if (!token) {
     throw new Error("[@octokit/auth-token] No token passed to createTokenAuth");
@@ -15,9 +15,14 @@ export const createTokenAuth: StrategyInterface = function createTokenAuth(
     );
   }
 
-  token = token.replace(/^(token|bearer) +/i, "");
+  token = toToken(token);
 
   return Object.assign(auth.bind(null, token), {
     hook: hook.bind(null, token),
   });
 };
+
+/** Turns a {@link BearerToken} into a {@link Token}. */
+function toToken(token: BearerToken | Token): Token {
+  return token.replace(/^(token|bearer) +/i, "") as Token;
+}
diff --git a/src/types.ts b/src/types.ts
index 4dfb392..e912e07 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -2,7 +2,7 @@ import type * as OctokitTypes from "@octokit/types";
 
 export type AnyResponse = OctokitTypes.OctokitResponse<any>;
 export type StrategyInterface = OctokitTypes.StrategyInterface<
-  [Token],
+  [Token | BearerToken],
   [],
   Authentication
 >;
@@ -12,7 +12,26 @@ export type RequestParameters = OctokitTypes.RequestParameters;
 export type RequestInterface = OctokitTypes.RequestInterface;
 export type Route = OctokitTypes.Route;
 
-export type Token = string;
+export type Token =
+  | PersonalAccessToken
+  | InstallallationTokenV1
+  | InstallallationToken
+  | ActionToken
+  | InstallationUserToServerToken
+  | OAuthToken;
+
+export type ActionToken = `ghs_${string}`;
+export type InstallallationToken = `ghs_${string}`;
+export type InstallallationTokenV1 = `v1.${string}`;
+export type InstallationUserToServerToken = `ghu_${string}`;
+export type OAuthToken = `${string}.${string}.${string}`;
+export type PersonalAccessToken = `ghp_${string}`;
+
+export type BearerToken =
+  | `bearer ${Token}`
+  | `Bearer ${Token}`
+  | `token ${Token}`
+  | `Token ${Token}`;
 
 export type OAuthTokenAuthentication = {
   type: "token";
diff --git a/test/index.test.ts b/test/index.test.ts
index d01e090..b8de4a8 100644
--- a/test/index.test.ts
+++ b/test/index.test.ts
@@ -62,6 +62,8 @@ test("User-to-server token (User authentication through app installation)", asyn
 });
 
 test("invalid token", async () => {
+  // @ts-expect-error Argument of type `"whatislove"` is not assignable to
+  // parameter of type`Token | BearerToken`.
   const auth = createTokenAuth("whatislove");
   const authentication = await auth();

It even highlights the "wrong token" in the tests. A type guard could be added to validate the token format client-side and to lower the burden of string->token conversion on library users.

Each token type can be summarily documented:

/**
 * Personal access tokens are an alternative to using passwords for
 * authentication to GitHub when using the [GitHub API](https://docs.github.com/en/rest/overview/authenticating-to-the-rest-api)
 * or the [command line](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#using-a-personal-access-token-on-the-command-line).
 *
 * @see https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token
 */
export type PersonalAccessToken = `ghp_${string}`;

There's even an article that points to the documentation of many token formats: https://github.blog/changelog/2021-03-31-authentication-token-format-updates-are-generally-available/

I'm not sure in which direction I should modify #400, I just made it for my own purposes, but if there's something clear that your team wants, I can accommodate so we can ship this as early as possible.

I think having these docs can heavily facilitate the usage of GitHub's API.

@wolfy1339
Copy link
Member

Instead of exporting everything, I think we should simply add in an entry to the exports map in the package.json that restores access

@wolfy1339
Copy link
Member

diff --git a/scripts/build.mjs b/scripts/build.mjs
index a392b44..55156f4 100644
--- a/scripts/build.mjs
+++ b/scripts/build.mjs
@@ -68,6 +68,9 @@ async function main() {
             types: "./dist-types/index.d.ts",
             import: "./dist-bundle/index.js",
           },
+          "./types": {
+            types: "./dist-types/types.d.ts",
+          }
         },
         sideEffects: false,
       },

This should do the trick

@kfcampbell kfcampbell moved this from 🆕 Triage to 🔥 Backlog in 🧰 Octokit Active Apr 1, 2024
@kfcampbell kfcampbell removed the Status: Triage This is being looked at and prioritized label Apr 1, 2024
@wolfy1339
Copy link
Member

I merged #404 that adds a /types export that resolves to dist-types/types.d.ts.

This issue should be resolved. Further discussion on improving the types, should be made in #400

@github-project-automation github-project-automation bot moved this from 🔥 Backlog to ✅ Done in 🧰 Octokit Active Apr 15, 2024
@wolfy1339 wolfy1339 linked a pull request Apr 15, 2024 that will close this issue
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Bug Something isn't working as documented
Projects
Archived in project
4 participants