Skip to content

Commit

Permalink
Add Atlassian OAuth provider (#1012)
Browse files Browse the repository at this point in the history
  • Loading branch information
pilcrowonpaper authored Aug 22, 2023
1 parent bd0393d commit 86c6b97
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .auri/$aydq7n8b.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
package: "@lucia-auth/oauth" # package name
type: "minor" # "major", "minor", "patch"
---

Add Atlassian provider
133 changes: 133 additions & 0 deletions packages/oauth/src/providers/atlassian.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import {
OAuth2ProviderAuth,
createOAuth2AuthorizationUrl,
validateOAuth2AuthorizationCode
} from "../core/oauth2.js";
import { ProviderUserAuth } from "../core/provider.js";
import { handleRequest, authorizationHeader } from "../utils/request.js";

import type { Auth } from "lucia";

type Config = {
clientId: string;
clientSecret: string;
redirectUri: string;
scope?: string[];
};

const PROVIDER_ID = "atlassian";

export const atlassian = <_Auth extends Auth = Auth>(
auth: _Auth,
config: Config
): AtlassianAuth<_Auth> => {
return new AtlassianAuth(auth, config);
};

export class AtlassianAuth<
_Auth extends Auth = Auth
> extends OAuth2ProviderAuth<AtlassianUserAuth<_Auth>> {
private config: Config;

constructor(auth: _Auth, config: Config) {
super(auth);

this.config = config;
}

public getAuthorizationUrl = async (): Promise<
readonly [url: URL, state: string]
> => {
const scopeConfig = this.config.scope ?? [];
const [url, state] = await createOAuth2AuthorizationUrl(
"https://auth.atlassian.com/authorize",
{
clientId: this.config.clientId,
redirectUri: this.config.redirectUri,
scope: ["read:me", ...scopeConfig]
}
);
url.searchParams.set("audience", "api.atlassian.com");
url.searchParams.set("prompt", "consent");
return [url, state];
};

public validateCallback = async (
code: string
): Promise<AtlassianUserAuth<_Auth>> => {
const atlassianTokens = await this.validateAuthorizationCode(code);
const atlassianUser = await getAtlassianUser(atlassianTokens.accessToken);
return new AtlassianUserAuth(this.auth, atlassianUser, atlassianTokens);
};

private validateAuthorizationCode = async (
code: string
): Promise<AtlassianTokens> => {
const tokens = await validateOAuth2AuthorizationCode<{
access_token: string;
expires_in: number;
refresh_token?: string;
}>(code, "https://auth.atlassian.com/token", {
clientId: this.config.clientId,
redirectUri: this.config.redirectUri,
clientPassword: {
authenticateWith: "client_secret",
clientSecret: this.config.clientSecret
}
});
return {
accessToken: tokens.access_token,
accessTokenExpiresIn: tokens.expires_in,
refreshToken: tokens.refresh_token ?? null
};
};
}

export class AtlassianUserAuth<
_Auth extends Auth = Auth
> extends ProviderUserAuth<_Auth> {
public atlassianTokens: AtlassianTokens;
public atlassianUser: AtlassianUser;

constructor(
auth: _Auth,
atlassianUser: AtlassianUser,
atlassianTokens: AtlassianTokens
) {
super(auth, PROVIDER_ID, atlassianUser.account_id);

this.atlassianTokens = atlassianTokens;
this.atlassianUser = atlassianUser;
}
}

const getAtlassianUser = async (
accessToken: string
): Promise<AtlassianUser> => {
const request = new Request("https://api.atlassian.com/me", {
headers: {
Authorization: authorizationHeader("bearer", accessToken)
}
});
const atlassianUser = await handleRequest<AtlassianUser>(request);
return atlassianUser;
};

export type AtlassianTokens = {
accessToken: string;
accessTokenExpiresIn: number;
refreshToken: string | null;
};

export type AtlassianUser = {
account_type: string;
account_id: string;
email: string;
name: string;
picture: string;
account_status: string;
nickname: string;
zoneinfo: string;
locale: string;
extended_profile?: Record<string, string>;
};
8 changes: 8 additions & 0 deletions packages/oauth/src/providers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ export type {
AppleUserAuth
} from "./apple.js";

export { atlassian } from "./atlassian.js";
export type {
AtlassianAuth,
AtlassianTokens,
AtlassianUser,
AtlassianUserAuth
} from "./atlassian.js";

export { auth0 } from "./auth0.js";
export type {
Auth0Auth,
Expand Down

0 comments on commit 86c6b97

Please sign in to comment.