Skip to content
This repository was archived by the owner on Mar 18, 2024. It is now read-only.

Commit 19b3417

Browse files
committed
update auth to work with MLTSHP
1 parent f738fed commit 19b3417

9 files changed

+168
-13
lines changed

.env.template

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
GITHUB_CLIENT_ID="YOUR_GIHUB_APPLICATION_ID"
2-
GITHUB_CLIENT_SECRET="YOUR_GIHUB_APPLICATION_SECRET"
1+
MLTSHP_CLIENT_ID="YOUR_MLTSHP_APPLICATION_ID"
2+
MLTSHP_CLIENT_SECRET="YOUR_MLTSHP_APPLICATION_SECRET"
33
NUXT_SECRET="YOUR_NUXT_SECRET"
44
ORIGIN="YOUR_ORIGIN"

package.json

+2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"devDependencies": {
2424
"@nuxt/eslint-config": "^0.1.1",
2525
"@sidebase/nuxt-auth": "^0.5.0-rc.0",
26+
"@types/crypto-js": "^4.1.1",
2627
"eslint": "^8.2.0",
2728
"eslint-config-airbnb-base": "15.0.0",
2829
"eslint-config-prettier": "^8.8.0",
@@ -37,6 +38,7 @@
3738
"stylelint-config-spaceninja": "^12.0.0"
3839
},
3940
"dependencies": {
41+
"crypto-js": "^4.1.1",
4042
"next-auth": "^4.22.0"
4143
}
4244
}

pages/api-routes.vue

+4-4
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@
1818
/>
1919
<APITableRow route="/signin" method="get" link="/api/auth/signin" />
2020
<APITableRow
21-
route="/signin/:provider"
21+
route="/signin/mltshp"
2222
method="post"
23-
link="/api/auth/signin/github"
23+
link="/api/auth/signin/mltshp"
2424
/>
2525
<APITableRow
26-
route="/callback/:provider"
26+
route="/callback/mltshp"
2727
method="get & post"
28-
link="/api/auth/callback/github"
28+
link="/api/auth/callback/mltshp"
2929
/>
3030
<APITableRow
3131
route="/signout"

pages/login.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<template>
33
<div>
44
<p>Sign-In:</p>
5-
<button @click="signIn('github')">Github</button>
5+
<button @click="signIn('mltshp')">MLTSHP</button>
66
</div>
77
</template>
88

server/api/auth/[...].ts

+39-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import GithubProvider from 'next-auth/providers/github';
21
import { NuxtAuthHandler } from '#auth';
32

43
export default NuxtAuthHandler({
@@ -8,11 +7,45 @@ export default NuxtAuthHandler({
87
// Change the default behavior to use `/login` as the path for the sign-in page
98
signIn: '/login',
109
},
10+
// @see https://next-auth.js.org/configuration/providers/oauth
1111
providers: [
12-
// @ts-expect-error You need to use .default here for it to work during SSR. May be fixed via Vite at some point
13-
GithubProvider.default({
14-
clientId: process.env.GITHUB_CLIENT_ID,
15-
clientSecret: process.env.GITHUB_CLIENT_SECRET,
16-
}),
12+
{
13+
id: 'mltshp',
14+
name: 'MLTSHP',
15+
type: 'oauth',
16+
clientId: process.env.MLTSHP_CLIENT_ID,
17+
clientSecret: process.env.MLTSHP_CLIENT_SECRET,
18+
authorization: {
19+
url: 'https://mltshp.com/api/authorize',
20+
params: {
21+
response_type: 'code',
22+
client_id: process.env.MLTSHP_CLIENT_ID,
23+
},
24+
},
25+
token: {
26+
url: 'https://mltshp.com/api/token',
27+
async request(context) {
28+
const tokens = await getMltshpToken(context);
29+
return { tokens };
30+
},
31+
},
32+
userinfo: {
33+
url: 'https://mltshp.com/api/user',
34+
async request(context) {
35+
const user = await getMltshpUser(context);
36+
return user;
37+
},
38+
},
39+
profile(profile) {
40+
return {
41+
id: profile.id,
42+
name: profile.name,
43+
image: profile.profile_image_url,
44+
about: profile.about,
45+
website: profile.website,
46+
shakes: profile.shakes,
47+
};
48+
},
49+
},
1750
],
1851
});

server/utils/getMltshpToken.ts

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/**
2+
* Get MLTSHP Token
3+
* @see https://mltshp.com/developers
4+
*/
5+
const getMltshpToken = (context: any) =>
6+
fetch(context.provider.token.url, {
7+
method: 'POST',
8+
headers: {
9+
'Content-Type': 'application/x-www-form-urlencoded',
10+
},
11+
body:
12+
`grant_type=authorization_code` +
13+
`&client_id=${context.provider.clientId}` +
14+
`&client_secret=${context.provider.clientSecret}` +
15+
`&code=${context.params.code}` +
16+
`&redirect_uri=${context.provider.callbackUrl}`,
17+
})
18+
.then((response) => {
19+
if (!response.ok) throw Error(response.statusText);
20+
return response.json();
21+
})
22+
.catch((error) => ({ error }));
23+
24+
export default getMltshpToken;

server/utils/getMltshpUser.ts

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// eslint-disable-next-line import/extensions
2+
import generateMltshpAuthString from '~/utils/generateMltshpAuthString';
3+
4+
/**
5+
* Get MLTSHP User
6+
* @see https://mltshp.com/developers
7+
*/
8+
const getMltshpUser = (context: any) => {
9+
const userInfoUrl = new URL(context.provider.userinfo.url);
10+
const userInfoPath = userInfoUrl.pathname;
11+
const authString = generateMltshpAuthString(context.tokens, userInfoPath);
12+
return fetch(context.provider.userinfo.url, {
13+
method: 'GET',
14+
headers: {
15+
'Content-Type': 'application/x-www-form-urlencoded',
16+
Authorization: authString,
17+
},
18+
})
19+
.then((response) => {
20+
if (!response.ok) throw Error(response.statusText);
21+
return response.json();
22+
})
23+
.catch((error) => ({ error }));
24+
};
25+
26+
export default getMltshpUser;

utils/generateMltshpAuthString.ts

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import hmacSHA1 from 'crypto-js/hmac-sha1';
2+
import base64 from 'crypto-js/enc-base64';
3+
import * as crypto from 'crypto';
4+
5+
interface TokenSet {
6+
access_token: string;
7+
secret: string;
8+
}
9+
10+
/**
11+
* Generate API Authorization String
12+
* We must create a signed message for the API using the following:
13+
* - An API access token
14+
* - A UTC timestamp (in seconds)
15+
* - A nonce (random string between 10 and 35 characters long)
16+
* Note: Don't use the UTC timestamp as a nonce!
17+
* - Your request method (GET/POST)
18+
* - The host (mltshp.com)
19+
* - The port (443 for SSL)
20+
* - The API endpoint path (/api/sharedfile/GA4)
21+
* @see https://mltshp.com/developers
22+
*/
23+
const generateMltshpAuthString = (
24+
token: TokenSet,
25+
path: string,
26+
method = 'GET'
27+
) => {
28+
const timestamp = Math.floor(Date.now() / 1000);
29+
const nonce = crypto.randomBytes(20).toString('hex');
30+
31+
// NOTE: using port 80 due to a bug in the API.
32+
// https://github.com/MLTSHP/mltshp/issues/567
33+
const port = 80;
34+
35+
// Normalize the message.
36+
// NOTE: The order, indentation, and linebreaks are important!
37+
const normalizedString = `${token.access_token}
38+
${timestamp}
39+
${nonce}
40+
${method}
41+
mltshp.com
42+
${port}
43+
${path}
44+
`;
45+
46+
// Create a signature by taking the normalizedString and use the secret to
47+
// construct a hash using SHA1 encoding, then Base64 the result.
48+
const hash = hmacSHA1(normalizedString, token.secret);
49+
const signature = base64.stringify(hash);
50+
51+
const authString =
52+
`MAC token=${token.access_token}, ` +
53+
`timestamp=${timestamp}, ` +
54+
`nonce=${nonce}, ` +
55+
`signature=${signature}`;
56+
57+
return authString;
58+
};
59+
60+
export default generateMltshpAuthString;

yarn.lock

+10
Original file line numberDiff line numberDiff line change
@@ -810,6 +810,11 @@
810810
resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad"
811811
integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==
812812

813+
"@types/crypto-js@^4.1.1":
814+
version "4.1.1"
815+
resolved "https://registry.yarnpkg.com/@types/crypto-js/-/crypto-js-4.1.1.tgz#602859584cecc91894eb23a4892f38cfa927890d"
816+
integrity sha512-BG7fQKZ689HIoc5h+6D2Dgq1fABRa0RbBWKBd9SP/MVRVXROflpm5fhwyATX5duFmbStzyzyycPB8qUYKDH3NA==
817+
813818
"@types/estree@*", "@types/estree@^1.0.0":
814819
version "1.0.0"
815820
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.0.tgz#5fb2e536c1ae9bf35366eed879e827fa59ca41c2"
@@ -1780,6 +1785,11 @@ cross-spawn@^7.0.2, cross-spawn@^7.0.3:
17801785
shebang-command "^2.0.0"
17811786
which "^2.0.1"
17821787

1788+
crypto-js@^4.1.1:
1789+
version "4.1.1"
1790+
resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.1.1.tgz#9e485bcf03521041bd85844786b83fb7619736cf"
1791+
integrity sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==
1792+
17831793
css-declaration-sorter@^6.3.1:
17841794
version "6.4.0"
17851795
resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.4.0.tgz#630618adc21724484b3e9505bce812def44000ad"

0 commit comments

Comments
 (0)