Skip to content

Commit

Permalink
feat(oauth): implement intercom (#6350)
Browse files Browse the repository at this point in the history
* rust part

* ts part

* good

---------

Co-authored-by: Henry Fontanier <[email protected]>
  • Loading branch information
fontanierh and Henry Fontanier authored Jul 19, 2024
1 parent af84621 commit 51ebbf6
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 7 deletions.
1 change: 1 addition & 0 deletions core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ pub mod oauth {
pub mod confluence;
pub mod github;
pub mod google_drive;
pub mod intercom;
pub mod notion;
pub mod slack;
pub mod utils;
Expand Down
6 changes: 3 additions & 3 deletions core/src/oauth/connection.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::oauth::{
providers::{
confluence::ConfluenceConnectionProvider, github::GithubConnectionProvider,
google_drive::GoogleDriveConnectionProvider, notion::NotionConnectionProvider,
slack::SlackConnectionProvider,
google_drive::GoogleDriveConnectionProvider, intercom::IntercomConnectionProvider,
notion::NotionConnectionProvider, slack::SlackConnectionProvider,
},
store::OAuthStore,
};
Expand Down Expand Up @@ -143,7 +143,7 @@ pub fn provider(t: ConnectionProvider) -> Box<dyn Provider + Sync + Send> {
ConnectionProvider::Confluence => Box::new(ConfluenceConnectionProvider::new()),
ConnectionProvider::Github => Box::new(GithubConnectionProvider::new()),
ConnectionProvider::GoogleDrive => Box::new(GoogleDriveConnectionProvider::new()),
ConnectionProvider::Intercom => unimplemented!(),
ConnectionProvider::Intercom => Box::new(IntercomConnectionProvider::new()),
ConnectionProvider::Notion => Box::new(NotionConnectionProvider::new()),
ConnectionProvider::Slack => Box::new(SlackConnectionProvider::new()),
}
Expand Down
82 changes: 82 additions & 0 deletions core/src/oauth/providers/intercom.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
use crate::oauth::{
connection::{Connection, ConnectionProvider, FinalizeResult, Provider, RefreshResult},
providers::utils::execute_request,
};
use anyhow::{anyhow, Result};
use async_trait::async_trait;
use lazy_static::lazy_static;
use serde_json::json;
use std::env;

lazy_static! {
static ref OAUTH_INTERCOM_CLIENT_ID: String = env::var("OAUTH_INTERCOM_CLIENT_ID").unwrap();
static ref OAUTH_INTERCOM_CLIENT_SECRET: String =
env::var("OAUTH_INTERCOM_CLIENT_SECRET").unwrap();
}

pub struct IntercomConnectionProvider {}

impl IntercomConnectionProvider {
pub fn new() -> Self {
IntercomConnectionProvider {}
}
}

#[async_trait]
impl Provider for IntercomConnectionProvider {
fn id(&self) -> ConnectionProvider {
ConnectionProvider::Intercom
}

async fn finalize(
&self,
_connection: &Connection,
code: &str,
redirect_uri: &str,
) -> Result<FinalizeResult> {
let body = json!({
"grant_type": "authorization_code",
"client_id": *OAUTH_INTERCOM_CLIENT_ID,
"client_secret": *OAUTH_INTERCOM_CLIENT_SECRET,
"code": code,
"redirect_uri": redirect_uri,
});

let req = reqwest::Client::new()
.post("https://api.intercom.io/auth/eagle/token")
.header("Content-Type", "application/json")
.json(&body);

let raw_json = execute_request(ConnectionProvider::Intercom, req).await?;

let access_token = match raw_json["access_token"].as_str() {
Some(token) => token,
None => Err(anyhow!("Missing `access_token` in response from Intercom"))?,
};

Ok(FinalizeResult {
redirect_uri: redirect_uri.to_string(),
code: code.to_string(),
access_token: access_token.to_string(),
access_token_expiry: None,
refresh_token: None,
raw_json,
})
}

async fn refresh(&self, _connection: &Connection) -> Result<RefreshResult> {
Err(anyhow!("Intercom access tokens do not expire"))?
}

fn scrubbed_raw_json(&self, raw_json: &serde_json::Value) -> Result<serde_json::Value> {
let raw_json = match raw_json.clone() {
serde_json::Value::Object(mut map) => {
map.remove("access_token");
map.remove("token");
serde_json::Value::Object(map)
}
_ => Err(anyhow!("Invalid raw_json, not an object"))?,
};
Ok(raw_json)
}
}
3 changes: 3 additions & 0 deletions front/lib/api/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ const config = {
getOAuthSlackClientId: (): string => {
return EnvironmentConfig.getEnvVariable("OAUTH_SLACK_CLIENT_ID");
},
getOAuthIntercomClientId: (): string => {
return EnvironmentConfig.getEnvVariable("OAUTH_INTERCOM_CLIENT_ID");
},
};

export default config;
17 changes: 13 additions & 4 deletions front/lib/api/oauth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,11 +177,20 @@ const PROVIDER_STRATEGIES: Record<
},
},
intercom: {
setupUri: () => {
throw new Error("Slack OAuth is not implemented");
setupUri: (connection) => {
return (
`https://app.intercom.com/oauth` +
`?client_id=${config.getOAuthIntercomClientId()}` +
`&state=${connection.connection_id}` +
`&redirect_uri=${encodeURIComponent(finalizeUriForProvider("intercom"))}`
);
},
codeFromQuery: (connection) => {
return getStringFromQuery(connection, "code");
},
connectionIdFromQuery: (connection) => {
return getStringFromQuery(connection, "state");
},
codeFromQuery: () => null,
connectionIdFromQuery: () => null,
},
microsoft: {
setupUri: () => {
Expand Down

0 comments on commit 51ebbf6

Please sign in to comment.