@shad-claiborne/hono-middleware-oidc 1.0.9 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -15,15 +15,24 @@
15
15
  ```
16
16
  ### Usage
17
17
  ```ts
18
- app.use('*', except('/auth/callback', withIdentity));
18
+ import {addIdentity, receiveAuth, handleFlow} from '@shad-claiborne/hono-middleware-oidc'
19
19
 
20
- app.use('/auth/callback', forAuthorization);
20
+ ...
21
21
 
22
+ // Add the identity claims to the request for all routes except the redirect URI
23
+ app.use('*', except('/auth/callback', addIdentity));
24
+
25
+ // The endpoint to which the authorization server provides the user's authorization
26
+ app.use('/auth/callback', receiveAuth);
27
+
28
+ // Send the browser to this endpoint to begin the authorization flow
29
+ // Note this endpoint assumes "addIdentity" precedes it
30
+ app.use('/login', handleFlow);
31
+
32
+ // Example ajax endpoint for getting the identity claims
22
33
  app.get('/async/api/identity', async (c) => {
23
34
  return c.json(c.get('identity'));
24
35
  });
25
36
 
26
- app.get('/', async (c) => {
27
- return c.text('hello world');
28
- });
37
+ ...
29
38
  ```
package/dist/index.d.ts CHANGED
@@ -1,4 +1,28 @@
1
1
  import { MiddlewareHandler } from "hono";
2
- export declare const withIdentity: MiddlewareHandler;
3
- export declare const forAuthorization: MiddlewareHandler;
2
+ /**
3
+ * handleFlow
4
+ * @param c
5
+ * @param next
6
+ * @returns
7
+ */
8
+ export declare const handleFlow: MiddlewareHandler;
9
+ /**
10
+ * addIdentity
11
+ * @param c
12
+ * @param next
13
+ * @returns
14
+ */
15
+ export declare const addIdentity: MiddlewareHandler;
16
+ /**
17
+ * checkIdentity
18
+ * @param c
19
+ * @returns
20
+ */
21
+ export declare const checkIdentity: MiddlewareHandler;
22
+ /**
23
+ * receiveAuth
24
+ * @param c
25
+ * @returns
26
+ */
27
+ export declare const receiveAuth: MiddlewareHandler;
4
28
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -2,8 +2,65 @@ import { deleteCookie, getSignedCookie, setSignedCookie } from "hono/cookie";
2
2
  import { createIdentityProvider, } from "@shad-claiborne/basic-oidc";
3
3
  import randomstring from "randomstring";
4
4
  import { env } from "hono/adapter";
5
- export const withIdentity = async (c, next) => {
6
- const { HONO_OIDC_ISSUER, HONO_OIDC_CLIENT_ID, HONO_OIDC_CLIENT_SECRET, HONO_OIDC_REDIRECT_URI, HONO_OIDC_COOKIE_SECRET, HONO_OIDC_ACCESS_TOKEN_COOKIE, HONO_OIDC_REFRESH_TOKEN_COOKIE, HONO_OIDC_ID_TOKEN_COOKIE, HONO_OIDC_CODE_VERIFIER_COOKIE, } = env(c);
5
+ import { HTTPException } from "hono/http-exception";
6
+ /**
7
+ * activateToken
8
+ * @param c
9
+ * @param tokenRes
10
+ */
11
+ const activateToken = async (c, provider, tokenResponse) => {
12
+ const { HONO_OIDC_COOKIE_SECRET, HONO_OIDC_ACCESS_TOKEN_COOKIE, HONO_OIDC_REFRESH_TOKEN_COOKIE, HONO_OIDC_ID_TOKEN_COOKIE, } = env(c);
13
+ if (tokenResponse.access_token) {
14
+ await setSignedCookie(c, HONO_OIDC_ACCESS_TOKEN_COOKIE, tokenResponse.access_token, HONO_OIDC_COOKIE_SECRET, { httpOnly: true, secure: true, sameSite: 'Lax', maxAge: tokenResponse.expires_in });
15
+ }
16
+ if (tokenResponse.refresh_token) {
17
+ const maxAge = tokenResponse.refresh_token_expires_in ?? (24 * 60 * 60);
18
+ await setSignedCookie(c, HONO_OIDC_REFRESH_TOKEN_COOKIE, tokenResponse.refresh_token, HONO_OIDC_COOKIE_SECRET, { httpOnly: true, secure: true, sameSite: 'Lax', maxAge });
19
+ }
20
+ if (tokenResponse.id_token) {
21
+ const idToken = await provider.decodeIdentityToken(tokenResponse.id_token);
22
+ const maxAge = idToken.exp - Math.floor(Date.now() / 1000);
23
+ await setSignedCookie(c, HONO_OIDC_ID_TOKEN_COOKIE, tokenResponse.id_token, HONO_OIDC_COOKIE_SECRET, { httpOnly: true, secure: true, sameSite: 'Lax', maxAge });
24
+ }
25
+ };
26
+ /**
27
+ * handleFlow
28
+ * @param c
29
+ * @param next
30
+ * @returns
31
+ */
32
+ export const handleFlow = async (c, next) => {
33
+ const { HONO_OIDC_ISSUER, HONO_OIDC_CLIENT_ID, HONO_OIDC_CLIENT_SECRET, HONO_OIDC_REDIRECT_URI, HONO_OIDC_COOKIE_SECRET, HONO_OIDC_CODE_VERIFIER_COOKIE, } = env(c);
34
+ const provider = await createIdentityProvider(HONO_OIDC_ISSUER);
35
+ const client = provider.createClient(HONO_OIDC_CLIENT_ID, HONO_OIDC_CLIENT_SECRET);
36
+ let id = c.get('identity');
37
+ if (!id) {
38
+ const stateId = randomstring.generate(5);
39
+ const state = { originUrl: c.get('originUrl') || c.req.url };
40
+ await setSignedCookie(c, `_authstate-${stateId}`, JSON.stringify(state), HONO_OIDC_COOKIE_SECRET, { httpOnly: true, secure: true, sameSite: 'Lax' });
41
+ const codeVerifier = randomstring.generate(16);
42
+ await setSignedCookie(c, HONO_OIDC_CODE_VERIFIER_COOKIE, codeVerifier, HONO_OIDC_COOKIE_SECRET, { httpOnly: true, secure: true, sameSite: 'Lax' });
43
+ const authRequest = client
44
+ .newAuthorizationRequest()
45
+ .setRedirectUri(HONO_OIDC_REDIRECT_URI)
46
+ .setResponseMode("query")
47
+ .setResponseType("code id_token")
48
+ .setScope(["profile"])
49
+ .setCodeChallenge(codeVerifier)
50
+ .setState(stateId);
51
+ const authRequestURL = authRequest.toURL();
52
+ return c.redirect(authRequestURL.toString());
53
+ }
54
+ await next();
55
+ };
56
+ /**
57
+ * addIdentity
58
+ * @param c
59
+ * @param next
60
+ * @returns
61
+ */
62
+ export const addIdentity = async (c, next) => {
63
+ const { HONO_OIDC_ISSUER, HONO_OIDC_CLIENT_ID, HONO_OIDC_CLIENT_SECRET, HONO_OIDC_COOKIE_SECRET, HONO_OIDC_ACCESS_TOKEN_COOKIE, HONO_OIDC_REFRESH_TOKEN_COOKIE, HONO_OIDC_ID_TOKEN_COOKIE, } = env(c);
7
64
  const provider = await createIdentityProvider(HONO_OIDC_ISSUER);
8
65
  const client = provider.createClient(HONO_OIDC_CLIENT_ID, HONO_OIDC_CLIENT_SECRET);
9
66
  const tokenSet = {
@@ -16,48 +73,41 @@ export const withIdentity = async (c, next) => {
16
73
  id = await provider.getIdentity(tokenSet);
17
74
  }
18
75
  catch (err) {
19
- id = null;
76
+ console.error(err);
20
77
  }
21
- if (id === null) {
78
+ if (!id) {
22
79
  try {
23
80
  const tokenResponse = await client.refreshAccess(tokenSet);
24
81
  id = await provider.getIdentity(tokenResponse);
25
- if (tokenResponse.access_token) {
26
- await setSignedCookie(c, HONO_OIDC_ACCESS_TOKEN_COOKIE, tokenResponse.access_token, HONO_OIDC_COOKIE_SECRET, { httpOnly: true, secure: true, sameSite: 'Lax' });
27
- }
28
- if (tokenResponse.refresh_token) {
29
- const maxAge = tokenResponse.refresh_token_expires_in ?? (24 * 60 * 60);
30
- await setSignedCookie(c, HONO_OIDC_REFRESH_TOKEN_COOKIE, tokenResponse.refresh_token, HONO_OIDC_COOKIE_SECRET, { httpOnly: true, secure: true, sameSite: 'Lax', maxAge });
31
- }
32
- if (tokenResponse.id_token) {
33
- const idToken = await provider.decodeIdentityToken(tokenResponse.id_token);
34
- const maxAge = idToken.exp - Math.floor(Date.now() / 1000);
35
- await setSignedCookie(c, HONO_OIDC_ID_TOKEN_COOKIE, tokenResponse.id_token, HONO_OIDC_COOKIE_SECRET, { httpOnly: true, secure: true, sameSite: 'Lax', maxAge });
36
- }
82
+ await activateToken(c, provider, tokenResponse);
37
83
  }
38
84
  catch (err) {
39
- const stateId = randomstring.generate(5);
40
- const state = { originUrl: c.get('originUrl') || c.req.url };
41
- await setSignedCookie(c, `_authstate-${stateId}`, JSON.stringify(state), HONO_OIDC_COOKIE_SECRET, { httpOnly: true, secure: true, sameSite: 'Lax' });
42
- const codeVerifier = randomstring.generate(16);
43
- await setSignedCookie(c, HONO_OIDC_CODE_VERIFIER_COOKIE, codeVerifier, HONO_OIDC_COOKIE_SECRET, { httpOnly: true, secure: true, sameSite: 'Lax' });
44
- const authRequest = client
45
- .newAuthorizationRequest()
46
- .setRedirectUri(HONO_OIDC_REDIRECT_URI)
47
- .setResponseMode("query")
48
- .setResponseType("code id_token")
49
- .setScope(["profile"])
50
- .setCodeChallenge(codeVerifier)
51
- .setState(stateId);
52
- const authRequestURL = authRequest.toURL();
53
- return c.redirect(authRequestURL.toString());
85
+ console.error(err);
54
86
  }
55
87
  }
56
- c.set("identity", id);
88
+ if (id) {
89
+ c.set("identity", id);
90
+ }
91
+ await next();
92
+ };
93
+ /**
94
+ * checkIdentity
95
+ * @param c
96
+ * @returns
97
+ */
98
+ export const checkIdentity = async (c, next) => {
99
+ const id = c.get('identity');
100
+ if (!id)
101
+ throw new HTTPException(401, { message: 'Unauthorized' });
57
102
  await next();
58
103
  };
59
- export const forAuthorization = async (c) => {
60
- const { HONO_OIDC_ISSUER, HONO_OIDC_CLIENT_ID, HONO_OIDC_CLIENT_SECRET, HONO_OIDC_REDIRECT_URI, HONO_OIDC_COOKIE_SECRET, HONO_OIDC_ACCESS_TOKEN_COOKIE, HONO_OIDC_REFRESH_TOKEN_COOKIE, HONO_OIDC_ID_TOKEN_COOKIE, HONO_OIDC_CODE_VERIFIER_COOKIE, } = env(c);
104
+ /**
105
+ * receiveAuth
106
+ * @param c
107
+ * @returns
108
+ */
109
+ export const receiveAuth = async (c) => {
110
+ const { HONO_OIDC_ISSUER, HONO_OIDC_CLIENT_ID, HONO_OIDC_CLIENT_SECRET, HONO_OIDC_REDIRECT_URI, HONO_OIDC_COOKIE_SECRET, HONO_OIDC_CODE_VERIFIER_COOKIE, } = env(c);
61
111
  const provider = await createIdentityProvider(HONO_OIDC_ISSUER);
62
112
  const client = provider.createClient(HONO_OIDC_CLIENT_ID, HONO_OIDC_CLIENT_SECRET);
63
113
  const requestURL = new URL(c.req.url), requestParams = requestURL.searchParams;
@@ -76,18 +126,7 @@ export const forAuthorization = async (c) => {
76
126
  if (codeVerifier === false || codeVerifier === undefined)
77
127
  throw new Error("code verifier cookie failed");
78
128
  const tokenResponse = await client.requestAccess(authResponse, { codeVerifier, redirectUri: HONO_OIDC_REDIRECT_URI });
79
- if (tokenResponse.access_token) {
80
- await setSignedCookie(c, HONO_OIDC_ACCESS_TOKEN_COOKIE, tokenResponse.access_token, HONO_OIDC_COOKIE_SECRET, { httpOnly: true, secure: true, sameSite: 'Lax', maxAge: tokenResponse.expires_in });
81
- }
82
- if (tokenResponse.refresh_token) {
83
- const maxAge = tokenResponse.refresh_token_expires_in ?? (24 * 60 * 60);
84
- await setSignedCookie(c, HONO_OIDC_REFRESH_TOKEN_COOKIE, tokenResponse.refresh_token, HONO_OIDC_COOKIE_SECRET, { httpOnly: true, secure: true, sameSite: 'Lax', maxAge });
85
- }
86
- if (tokenResponse.id_token) {
87
- const idToken = await provider.decodeIdentityToken(tokenResponse.id_token);
88
- const maxAge = idToken.exp - Math.floor(Date.now() / 1000);
89
- await setSignedCookie(c, HONO_OIDC_ID_TOKEN_COOKIE, tokenResponse.id_token, HONO_OIDC_COOKIE_SECRET, { httpOnly: true, secure: true, sameSite: 'Lax', maxAge });
90
- }
129
+ await activateToken(c, provider, tokenResponse);
91
130
  return c.redirect(state.originUrl);
92
131
  };
93
132
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shad-claiborne/hono-middleware-oidc",
3
- "version": "1.0.9",
3
+ "version": "1.1.1",
4
4
  "description": "OIDC middleware for Hono",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",