Use OAuth with Cloudflare Workers
Examples below have been tested with Github. It should work with other oauth providers with minor changes.
The configuration parameters are passed in an OAuthConfig
struct to initialize the service.
The example below sets the secret parameters in the environment, so they aren't part of the compiled wasm binary.
env_json
containing json data, which will be parsed
by the worker.At the bottom of wrangler.toml, add the following.
```toml [vars]
envjson= """{ "oauth": { "appurl": "https://app.example.com/", "authorizedusers": [ "gituser" ], "clientid" : "0000", "clientsecret": "0000", "statesecret": "0000", "corsorigins": [ "https://app.example.com", "http://localhost:3000" ], "loggedoutappurl": "https://app.example.com/", "sessionpathprefix": "/private/", "session_secret": "0000" } } ```
app_url
: base url for your appclient_id
, client_secret
: github api id and secretstate_secret
, session_secret
: 32-bit encryption keys
as 64 hex digits. One way to create these on unix:
head --bytes 32 /dev/urandom | hexdump -ve '1/1 "%.2x"' && echo
logged_out_app_url
: where user will be redirected after logout
session_path_prefix
: any url beginning with this will have its session cookie set```rust2018
extern "C" { static env_json: String; }
pub async fn mainentry(req: Jsvalue) -> Result
let oauth_config = build_oauth_config(&settings.oauth)?;
let oauth_handler = OAuthHandler::init(oauth_config)
.map_err(|e| JsValue::from(&format!("OAuthHandler init error: {}", e.to_string())))?;
wasm_service::service_request(
req,
ServiceConfig {
logger,
handlers: vec![
Box::new(MyHandler(oauth_handler))
],
..Default::default()
}
).await
}
fn buildoauthconfig(env: &Oauth) -> Result
let config = OAuthConfig {
app_url: env.app_url.to_string(),
logged_out_app_url: env.logged_out_app_url.to_string(),
authorize_url_path: "/authorize".to_string(),
code_url_path: "/code".to_string(),
login_failed_url_path: "/login-failed".to_string(),
logout_url_path: "/logout".to_string(),
auth_checker: Box::new(allow),
client_id: env.client_id.to_string(),
client_secret: env.client_secret.to_string(),
state_secret: key_from_hex(&env.state_secret, 32).map_err(JsValue::from)?,
session_secret: key_from_hex(&env.session_secret, 32).map_err(JsValue::from)?,
session_cookie_path_prefix: env.session_path_prefix.to_string(),
cors_origins: env.cors_origins.clone(), // .iter().map(|v| v.as_ref()).collect(),
..Default::default()
};
Ok(config)
}
/// load config from environment
pub(crate) fn load(json: &str) -> Result
pub struct Config { pub oauth: Oauth, }
pub struct Oauth {
pub clientid: String,
pub clientsecret: String,
pub statesecret: String,
pub sessionsecret: String,
pub sessionpathprefix: String,
pub appurl: String,
pub loggedoutappurl: String,
pub corsorigins: Vec
Update the handler function as follows ```rust2018 async fn handle(&self, req: &Request, mut ctx: &mut Context) -> Result<(), HandlerReturn> {
// urls beginning with sessionpathprefix require authentication if req.url().path().startswith("/private/") { let _session = self.oauthhandler.verifyauthuser(req, &mut ctx)?; // user is authenticated!! // ...
} else { // handle urls not requiring authentication // ... }
// let oauth handler process its urls if ctx.response().isunset() { if self.oauthhandler.wouldhandle(&req) { // handle oauth processing for /code, /authorize, /login-failed, etc. self.oauthhandler.handle(req, &mut ctx).await?; } } Ok(()) } ```