oauth2-server-grant-type-apple
Version:
Apple grant type for @node-oauth/oauth2-server
75 lines (74 loc) • 2.86 kB
JavaScript
import { AbstractGrantType, InvalidArgumentError, InvalidRequestError, InvalidTokenError } from "@node-oauth/oauth2-server";
import { createRemoteJWKSet, jwtVerify } from "jose";
//#region src/verify-token.ts
const JWKS = createRemoteJWKSet(new URL("https://appleid.apple.com/auth/keys"));
const ISSUER = "https://appleid.apple.com";
const verifyToken = async ({ token, audience }) => {
const { payload } = await jwtVerify(token, JWKS, {
algorithms: ["RS256"],
issuer: ISSUER,
audience
});
return payload;
};
//#endregion
//#region src/apple-grant-type.ts
var AppleGrantType = class extends AbstractGrantType {
constructor(options) {
super(options);
this.appIds = [];
if (!options.model) throw new InvalidArgumentError("Missing parameter: `model`");
if (!options.model.getUserWithApple) throw new InvalidArgumentError("Invalid argument: model does not implement `getUserWithApple()`");
if (!options.model.saveToken) throw new InvalidArgumentError("Invalid argument: model does not implement `saveToken()`");
this.model = options.model;
const appId = this.model.appleGrantType?.appId;
if (appId) this.appIds = Array.isArray(appId) ? appId : [appId];
if (this.appIds.length === 0) throw new InvalidArgumentError("Invalid argument: Apple valid appId must be provided in options");
this.handle = this.handle.bind(this);
this.getUser = this.getUser.bind(this);
this.saveToken = this.saveToken.bind(this);
}
async handle(request, client) {
if (!request) throw new InvalidArgumentError("Missing parameter: `request`");
if (!client) throw new InvalidArgumentError("Missing parameter: `client`");
const scope = this.getScope(request);
const user = await this.getUser(request);
return await this.saveToken(user, client, scope);
}
async getUser(request) {
const token = request.body.apple_token;
const name = request.body.name;
if (!token) throw new InvalidRequestError("Missing parameter: `apple_token`");
let data;
try {
data = await verifyToken({
token,
audience: this.appIds
});
} catch {
throw new InvalidTokenError("Apple id token is invalid or expired");
}
return await this.model.getUserWithApple({
name,
...data
});
}
async saveToken(user, client, scope) {
const validatedScope = await this.validateScope(user, client, scope);
const accessToken = await this.generateAccessToken(client, user, scope);
const refreshToken = await this.generateRefreshToken(client, user, scope);
const token = {
accessToken,
accessTokenExpiresAt: this.getAccessTokenExpiresAt(),
refreshToken,
refreshTokenExpiresAt: this.getRefreshTokenExpiresAt(),
scope: validatedScope || [],
user: { id: user.id },
client
};
return await this.model.saveToken(token, client, user);
}
};
//#endregion
export { AppleGrantType, verifyToken };
//# sourceMappingURL=index.js.map