Skip to content

Commit

Permalink
Improve access token function to be more like Meteor's implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
StorytellerCZ committed Dec 21, 2022
1 parent 28ff157 commit 9e1599d
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 63 deletions.
2 changes: 1 addition & 1 deletion line-oauth/.versions
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ retry@1.1.0
routepolicy@1.1.1
service-configuration@1.3.1
socket-stream-client@0.5.0
storyteller:line-oauth@1.3.0
storyteller:line-oauth@1.3.2
tracker@1.2.1
typescript@4.6.4
underscore@1.0.11
Expand Down
8 changes: 7 additions & 1 deletion line-oauth/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog
## 1.3.0 - 2022-12-13
## 1.3.2 - 2022-12-21
* Improve access token function to be more like Meteor's implementation

## 1.3.1 - 2022-12-21
* Fix bad import

## 1.3.0 - 2022-12-21
* Compatibility with Meteor 2.9
* Typescript conversion

Expand Down
128 changes: 68 additions & 60 deletions line-oauth/line_server.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { Meteor } from 'meteor/meteor';
import { fetch, URLSearchParams } from 'meteor/fetch';
import { ServiceConfiguration } from 'meteor/service-configuration';
import { fetch } from 'meteor/fetch'
import { URLSearchParams } from 'meteor/url'
import { ServiceConfiguration } from 'meteor/service-configuration'
import { OAuth } from 'meteor/oauth'
const jsonwebtoken = Npm.require('jsonwebtoken');
Line = {};

const jsonwebtoken = Npm.require('jsonwebtoken')
Line = {}

OAuth.registerService('line', 2, null, async (query) => {
const responseFunc = await getAccessToken(query);
const response = responseFunc(query);
const identity = getIdentity(response.id_token);
const response = await getAccessToken(query)
const identity = getIdentity(response.id_token)
let data = {
serviceData: {
id: identity.sub,
Expand All @@ -20,76 +20,84 @@ OAuth.registerService('line', 2, null, async (query) => {
tokenType: response.token_type
},
options: { profile: { name: identity.name, avatar: identity.picture } }
};
}

if (identity.email) {
data.serviceData.email = identity.email;
data.serviceData.email = identity.email
}

return data;
});
return data
})

const getAccessToken = async (query) => {
const config = ServiceConfiguration.configurations.findOne({ service: 'line' });
if (!config) throw new ServiceConfiguration.ConfigError();
let request;
try {
const content = new URLSearchParams({
grant_type: 'authorization_code',
code: query.code,
client_id: config.channelId,
client_secret: OAuth.openSecret(config.secret),
redirect_uri: OAuth._redirectUri('line', config)
});
request = await fetch('https://api.line.me/oauth2/v2.1/token', {
method: 'POST',
headers: { Accept: 'application/json', 'Content-Type': 'application/x-www-form-urlencoded' },
body: content,
redirect: 'follow',
jar: false
});
} catch (err) {
throw Object.assign(new Error(`Failed to complete OAuth handshake with LINE. ${err.message}`), {
response: err.response
});
}

const response = await request.json();

if (response.error) {
// if the response was a json object with an error attribute
throw new Error(`Failed to complete OAuth handshake with LINE. ${response.error_description}`);
} else {
return response
}
};
const config = await ServiceConfiguration.configurations.findOneAsync({
service: 'line'
})
if (!config) throw new ServiceConfiguration.ConfigError()
const content = new URLSearchParams({
grant_type: 'authorization_code',
code: query.code,
client_id: config.channelId,
client_secret: OAuth.openSecret(config.secret),
redirect_uri: OAuth._redirectUri('line', config)
})
return fetch('https://api.line.me/oauth2/v2.1/token', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/x-www-form-urlencoded'
},
body: content,
redirect: 'follow',
jar: false
})
.then((res) => res.json())
.then((data) => {
return data
})
.catch((err) => {
throw Object.assign(
new Error(
`Failed to complete OAuth handshake with LINE. ${err.message}`
),
{
response: err.response
}
)
})
}

const getIdentity = token => {
const config = ServiceConfiguration.configurations.findOne({ service: 'line' });
if (!config) throw new ServiceConfiguration.ConfigError();
let response;
const getIdentity = (token) => {
const config = ServiceConfiguration.configurations.findOne({
service: 'line'
})
if (!config) throw new ServiceConfiguration.ConfigError()
let response

let secret = config.secret;
let secret = config.secret
if (typeof secret === 'object' && Package['oauth-encryption']) {
import { OAuthEncryption } from 'meteor/oauth-encryption';
import { OAuthEncryption } from 'meteor/oauth-encryption'

secret = OAuthEncryption.open(secret);
secret = OAuthEncryption.open(secret)
}

try {
response = jsonwebtoken.verify(token, secret, {
audience: config.channelId,
issuer: 'https://access.line.me',
algorithms: ['HS256'],
algorithms: ['HS256']
// nonce: // TODO setup and check nonce for additional security
});
})
} catch (err) {
throw Object.assign(new Error(`Couldn't decode JWT from LINE. ${err.message}`), {
response: err.response
});
throw Object.assign(
new Error(`Couldn't decode JWT from LINE. ${err.message}`),
{
response: err.response
}
)
}
return response;
};
return response
}

Line.retrieveCredential = (credentialToken, credentialSecret) =>
OAuth.retrieveCredential(credentialToken, credentialSecret);
OAuth.retrieveCredential(credentialToken, credentialSecret)
2 changes: 1 addition & 1 deletion line-oauth/package.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Package.describe({
name: 'storyteller:line-oauth',
summary: 'LINE OAuth flow',
version: '1.3.0',
version: '1.3.2',
git: 'https://github.com/StorytellerCZ/meteor-accounts-line'
});

Expand Down

0 comments on commit 9e1599d

Please sign in to comment.