{"id":13994574,"url":"https://github.com/kilork/openid","last_synced_at":"2026-02-28T23:05:25.750Z","repository":{"id":50367889,"uuid":"244113568","full_name":"kilork/openid","owner":"kilork","description":"OpenID Connect Rust Library","archived":false,"fork":false,"pushed_at":"2026-02-15T23:39:25.000Z","size":228,"stargazers_count":83,"open_issues_count":15,"forks_count":28,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-02-16T06:49:31.131Z","etag":null,"topics":["authentication","oauth2","oidc","openid","openid-connect","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kilork.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"COPYING","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"kilork","ko_fi":"kilork"}},"created_at":"2020-03-01T08:31:15.000Z","updated_at":"2026-02-15T23:39:29.000Z","dependencies_parsed_at":"2024-01-18T05:11:12.537Z","dependency_job_id":"4f1d5891-ef76-49b0-9c25-fd8974c35cd9","html_url":"https://github.com/kilork/openid","commit_stats":{"total_commits":66,"total_committers":10,"mean_commits":6.6,"dds":0.5606060606060606,"last_synced_commit":"e5ab78061129111bd4b511e88bacf2a5f8d31713"},"previous_names":[],"tags_count":36,"template":false,"template_full_name":null,"purl":"pkg:github/kilork/openid","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kilork%2Fopenid","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kilork%2Fopenid/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kilork%2Fopenid/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kilork%2Fopenid/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kilork","download_url":"https://codeload.github.com/kilork/openid/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kilork%2Fopenid/sbom","scorecard":{"id":560209,"data":{"date":"2025-08-11","repo":{"name":"github.com/kilork/openid","commit":"93223564255959afbba085c3ea7de8193cd62a3a"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.5,"checks":[{"name":"Code-Review","score":1,"reason":"Found 4/30 approved changesets -- score normalized to 1","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":10,"reason":"9 commit(s) and 4 issue activity found in the last 90 days -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/ci.yml:1","Warn: no topLevel permission defined: .github/workflows/release.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/kilork/openid/ci.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/kilork/openid/ci.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/kilork/openid/release.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/release.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/kilork/openid/release.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:24: update your workflow using https://app.stepsecurity.io/secureworkflow/kilork/openid/release.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/release.yml:26: update your workflow using https://app.stepsecurity.io/secureworkflow/kilork/openid/release.yml/master?enable=pin","Info:   0 out of   3 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   3 third-party GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: UNLICENSE:0","Info: FSF or OSI recognized license: The Unlicense: UNLICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 6 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-20T13:27:07.173Z","repository_id":50367889,"created_at":"2025-08-20T13:27:07.173Z","updated_at":"2025-08-20T13:27:07.173Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29954583,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-28T22:53:01.873Z","status":"ssl_error","status_checked_at":"2026-02-28T22:52:50.699Z","response_time":90,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["authentication","oauth2","oidc","openid","openid-connect","rust"],"created_at":"2024-08-09T14:02:57.330Z","updated_at":"2026-02-28T23:05:25.734Z","avatar_url":"https://github.com/kilork.png","language":"Rust","funding_links":["https://github.com/sponsors/kilork","https://ko-fi.com/kilork"],"categories":["Rust"],"sub_categories":[],"readme":"# OpenID Connect \u0026 Discovery client library using async / await\n\n## Legal\n\nDual-licensed under `MIT` or the [UNLICENSE](http://unlicense.org/).\n\n## Features\n\nImplements [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html) and [OpenID Connect Discovery 1.0](https://openid.net/specs/openid-connect-discovery-1_0.html).\n\nImplements [UMA2](https://docs.kantarainitiative.org/uma/wg/oauth-uma-federated-authz-2.0-09.html) - User Managed Access, an extension to OIDC/OAuth2. Use feature flag `uma2` to enable this feature.\n\nImplements [OAuth 2.0 Token Introspection](https://datatracker.ietf.org/doc/html/rfc7662).\n\nImplements [PKCE: Proof Key for Code Exchange by OAuth Public Clients](https://datatracker.ietf.org/doc/html/rfc7636). PKCE is enabled by default. Please note that PKCE is not rotating keys, but rather using a single key pair for the entire lifetime of the application. One can rotate the key pair by calling the `refresh_pkce` method on client. Ideally, this should be done after each generation of authorization url.\n\nIt supports Microsoft OIDC with feature `microsoft`. This adds methods for authentication and token validation, those skip issuer check.\n\nOriginally developed as a quick adaptation to leverage async/await functionality, based on [inth-oauth2](https://crates.io/crates/inth-oauth2) and [oidc](https://crates.io/crates/oidc), the library has since evolved into a mature and robust solution, offering expanded features and improved performance.\n\nUsing [reqwest](https://crates.io/crates/reqwest) for the HTTP client and [biscuit](https://crates.io/crates/biscuit) for Javascript Object Signing and Encryption (JOSE).\n\n## Support:\n\nYou can contribute to the ongoing development and maintenance of OpenID library in various ways:\n\n### Sponsorship\n\nYour support, no matter how big or small, helps sustain the project and ensures its continued improvement. Reach out to explore sponsorship opportunities.\n\n### Feedback\n\nWhether you are a developer, user, or enthusiast, your feedback is invaluable. Share your thoughts, suggestions, and ideas to help shape the future of the library.\n\n### Contribution\n\nIf you're passionate about open-source and have skills to share, consider contributing to the project. Every contribution counts!\n\nThank you for being part of OpenID community. Together, we are making authentication processes more accessible, reliable, and efficient for everyone.\n\n## Usage\n\nAdd dependency to Cargo.toml:\n\n```toml\n[dependencies]\nopenid = \"0.23\"\n```\n\nBy default we use native tls, if you want to use `rustls`:\n\n```toml\n[dependencies]\nopenid = { version = \"0.23\", default-features = false, features = [\"rustls\"] }\n```\n\n### Use case: [Warp](https://crates.io/crates/warp) web server with [JHipster](https://www.jhipster.tech/) generated frontend and [Google OpenID Connect](https://developers.google.com/identity/protocols/OpenIDConnect)\n\nThis example provides only Rust part, assuming just default JHipster frontend settings.\n\nin Cargo.toml:\n\n```toml\n[dependencies]\nanyhow = \"1.0\"\ncookie = \"0.18\"\ndotenv = \"0.15\"\nlog = \"0.4\"\nopenid = \"0.23\"\npretty_env_logger = \"0.5\"\nreqwest = \"0.13\"\nserde = { version = \"1\", default-features = false, features = [ \"derive\" ] }\nserde_json = \"1\"\ntokio = { version = \"1\", default-features = false, features = [ \"rt-multi-thread\", \"macros\" ] }\nuuid = { version = \"1\", default-features = false, features = [ \"v4\" ] }\nwarp = { version = \"0.4\", default-features = false, features = [ \"server\" ] }\n```\n\nin src/main.rs:\n\n```rust, compile_fail\nuse std::{convert::Infallible, env, net::SocketAddr, sync::Arc};\n\nuse cookie::time::Duration;\nuse log::{error, info};\nuse tokio::sync::RwLock;\nuse warp::{\n    Filter, Rejection, Reply,\n    http::{Response, StatusCode},\n    reject,\n};\n\nuse openid::{Client, Discovered, DiscoveredClient, Options, StandardClaims, Token, Userinfo};\nuse openid_examples::{\n    INDEX_HTML,\n    entity::{LoginQuery, Sessions, User},\n};\n\ntype OpenIDClient = Client\u003cDiscovered, StandardClaims\u003e;\n\nconst EXAMPLE_COOKIE: \u0026str = \"openid_warp_example\";\n\n#[tokio::main]\nasync fn main() -\u003e anyhow::Result\u003c()\u003e {\n    dotenv::dotenv().ok();\n\n    pretty_env_logger::init();\n\n    let client_id = env::var(\"CLIENT_ID\").expect(\"\u003cclient id\u003e for your provider\");\n    let client_secret = env::var(\"CLIENT_SECRET\").ok();\n    let issuer_url =\n        env::var(\"ISSUER\").unwrap_or_else(|_| \"https://accounts.google.com\".to_string());\n    let redirect = Some(host(\"/login/oauth2/code/oidc\"));\n    let issuer = reqwest::Url::parse(\u0026issuer_url)?;\n    let listen: SocketAddr = env::var(\"LISTEN\")\n        .unwrap_or_else(|_| \"127.0.0.1:8080\".to_string())\n        .parse()?;\n\n    info!(\"redirect: {redirect:?}\");\n    info!(\"issuer: {issuer}\");\n\n    let client = Arc::new(\n        DiscoveredClient::discover(\n            client_id,\n            client_secret.unwrap_or_default(),\n            redirect,\n            issuer,\n        )\n        .await?,\n    );\n\n    info!(\"discovered config: {:?}\", client.config());\n\n    let with_client = |client: Arc\u003cClient\u003c_\u003e\u003e| warp::any().map(move || client.clone());\n\n    let sessions = Arc::new(RwLock::new(Sessions::default()));\n\n    let with_sessions = |sessions: Arc\u003cRwLock\u003cSessions\u003e\u003e| warp::any().map(move || sessions.clone());\n\n    let index = warp::path::end()\n        .and(warp::get())\n        .map(|| warp::reply::html(INDEX_HTML));\n\n    let authorize = warp::path!(\"oauth2\" / \"authorization\" / \"oidc\")\n        .and(warp::get())\n        .and(with_client(client.clone()))\n        .and_then(reply_authorize);\n\n    let login = warp::path!(\"login\" / \"oauth2\" / \"code\" / \"oidc\")\n        .and(warp::get())\n        .and(with_client(client.clone()))\n        .and(warp::query::\u003cLoginQuery\u003e())\n        .and(with_sessions(sessions.clone()))\n        .and_then(reply_login);\n\n    let logout = warp::path!(\"logout\")\n        .and(warp::get())\n        .and(with_client(client.clone()))\n        .and(warp::cookie::optional(EXAMPLE_COOKIE))\n        .and(with_sessions(sessions.clone()))\n        .and_then(reply_logout);\n\n    let api_account = warp::path!(\"api\" / \"account\")\n        .and(warp::get())\n        .and(with_user(sessions))\n        .map(|user: User| warp::reply::json(\u0026user));\n\n    let routes = index\n        .or(authorize)\n        .or(login)\n        .or(logout)\n        .or(api_account)\n        .recover(handle_rejections);\n\n    let logged_routes = routes.with(warp::log(\"openid_warp_example\"));\n\n    warp::serve(logged_routes).run(listen).await;\n\n    Ok(())\n}\n\nasync fn request_token(\n    oidc_client: \u0026OpenIDClient,\n    login_query: \u0026LoginQuery,\n) -\u003e anyhow::Result\u003cOption\u003c(Token, Userinfo)\u003e\u003e {\n    let mut token: Token = oidc_client.request_token(\u0026login_query.code).await?.into();\n\n    if let Some(id_token) = token.id_token.as_mut() {\n        oidc_client.decode_token(id_token)?;\n        oidc_client.validate_token(id_token, None, None)?;\n        info!(\"token: {id_token:?}\");\n    } else {\n        return Ok(None);\n    }\n\n    let userinfo = oidc_client.request_userinfo(\u0026token).await?;\n\n    info!(\"user info: {userinfo:?}\");\n\n    Ok(Some((token, userinfo)))\n}\n\nasync fn reply_login(\n    oidc_client: Arc\u003cOpenIDClient\u003e,\n    login_query: LoginQuery,\n    sessions: Arc\u003cRwLock\u003cSessions\u003e\u003e,\n) -\u003e Result\u003cimpl warp::Reply, Infallible\u003e {\n    let request_token = request_token(\u0026oidc_client, \u0026login_query).await;\n    match request_token {\n        Ok(Some((token, user_info))) =\u003e {\n            let id = uuid::Uuid::new_v4().to_string();\n\n            let login = user_info.preferred_username.clone();\n            let email = user_info.email.clone();\n\n            let user = User {\n                id: user_info.sub.clone(),\n                login,\n                last_name: user_info.family_name.clone(),\n                first_name: user_info.name.clone(),\n                email,\n                activated: user_info.email_verified,\n                image_url: user_info.picture.clone().map(|x| x.to_string()),\n                lang_key: Some(\"en\".to_string()),\n                authorities: vec![\"ROLE_USER\".to_string()],\n            };\n\n            let authorization_cookie = ::cookie::Cookie::build((EXAMPLE_COOKIE, \u0026id))\n                .path(\"/\")\n                .http_only(true)\n                .build()\n                .to_string();\n\n            sessions\n                .write()\n                .await\n                .map\n                .insert(id, (user, token, user_info));\n\n            let redirect_url = login_query.state.clone().unwrap_or_else(|| host(\"/\"));\n\n            Ok(Response::builder()\n                .status(StatusCode::MOVED_PERMANENTLY)\n                .header(warp::http::header::LOCATION, redirect_url)\n                .header(warp::http::header::SET_COOKIE, authorization_cookie)\n                .body(\"\")\n                .unwrap())\n        }\n        Ok(None) =\u003e {\n            error!(\"login error in call: no id_token found\");\n\n            response_unauthorized()\n        }\n        Err(err) =\u003e {\n            error!(\"login error in call: {err:?}\");\n\n            response_unauthorized()\n        }\n    }\n}\n\nfn response_unauthorized() -\u003e Result\u003cResponse\u003c\u0026'static str\u003e, Infallible\u003e {\n    Ok(Response::builder()\n        .status(StatusCode::UNAUTHORIZED)\n        .body(\"\")\n        .unwrap())\n}\n\nasync fn reply_logout(\n    oidc_client: Arc\u003cOpenIDClient\u003e,\n    session_id: Option\u003cString\u003e,\n    sessions: Arc\u003cRwLock\u003cSessions\u003e\u003e,\n) -\u003e Result\u003cimpl warp::Reply, Infallible\u003e {\n    let Some(id) = session_id else {\n        return response_unauthorized();\n    };\n\n    let session_removed = sessions.write().await.map.remove(\u0026id);\n\n    if let Some(id_token) = session_removed.and_then(|(_, token, _)| token.bearer.id_token) {\n        let authorization_cookie = ::cookie::Cookie::build((EXAMPLE_COOKIE, \u0026id))\n            .path(\"/\")\n            .http_only(true)\n            .max_age(Duration::seconds(-1))\n            .build()\n            .to_string();\n\n        let return_redirect_url = host(\"/\");\n\n        let redirect_url = oidc_client\n            .config()\n            .end_session_endpoint\n            .clone()\n            .map(|mut logout_provider_endpoint| {\n                logout_provider_endpoint\n                    .query_pairs_mut()\n                    .append_pair(\"id_token_hint\", \u0026id_token)\n                    .append_pair(\"post_logout_redirect_uri\", \u0026return_redirect_url);\n                logout_provider_endpoint.to_string()\n            })\n            .unwrap_or_else(|| return_redirect_url);\n\n        info!(\"logout redirect url: {redirect_url}\");\n\n        Ok(Response::builder()\n            .status(StatusCode::FOUND)\n            .header(warp::http::header::LOCATION, redirect_url)\n            .header(warp::http::header::SET_COOKIE, authorization_cookie)\n            .body(\"\")\n            .unwrap())\n    } else {\n        response_unauthorized()\n    }\n}\n\nasync fn reply_authorize(oidc_client: Arc\u003cOpenIDClient\u003e) -\u003e Result\u003cimpl warp::Reply, Infallible\u003e {\n    let origin_url = env::var(\"ORIGIN\").unwrap_or_else(|_| host(\"\"));\n\n    let auth_url = oidc_client.auth_url(\u0026Options {\n        scope: Some(\"openid email profile\".into()),\n        state: Some(origin_url),\n        ..Default::default()\n    });\n\n    info!(\"authorize: {auth_url}\");\n\n    let url: String = auth_url.into();\n\n    Ok(warp::reply::with_header(\n        StatusCode::FOUND,\n        warp::http::header::LOCATION,\n        url,\n    ))\n}\n\n#[derive(Debug)]\nstruct Unauthorized;\n\nimpl reject::Reject for Unauthorized {}\n\nasync fn extract_user(\n    session_id: Option\u003cString\u003e,\n    sessions: Arc\u003cRwLock\u003cSessions\u003e\u003e,\n) -\u003e Result\u003cUser, Rejection\u003e {\n    if let Some(session_id) = session_id {\n        if let Some((user, _, _)) = sessions.read().await.map.get(\u0026session_id) {\n            Ok(user.clone())\n        } else {\n            Err(warp::reject::custom(Unauthorized))\n        }\n    } else {\n        Err(warp::reject::custom(Unauthorized))\n    }\n}\n\nfn with_user(\n    sessions: Arc\u003cRwLock\u003cSessions\u003e\u003e,\n) -\u003e impl Filter\u003cExtract = (User,), Error = Rejection\u003e + Clone {\n    warp::cookie::optional(EXAMPLE_COOKIE)\n        .and(warp::any().map(move || sessions.clone()))\n        .and_then(extract_user)\n}\n\nasync fn handle_rejections(err: Rejection) -\u003e Result\u003cimpl Reply, Infallible\u003e {\n    let code = if err.is_not_found() {\n        StatusCode::NOT_FOUND\n    } else if let Some(Unauthorized) = err.find() {\n        StatusCode::UNAUTHORIZED\n    } else {\n        StatusCode::INTERNAL_SERVER_ERROR\n    };\n\n    Ok(warp::reply::with_status(warp::reply(), code))\n}\n\n/// This host is the address, where user would be redirected after initial authorization.\n/// For DEV environment with WebPack this is usually something like `http://localhost:9000`.\n/// We are using `http://localhost:8080` in all-in-one example.\npub fn host(path: \u0026str) -\u003e String {\n    env::var(\"REDIRECT_URL\").unwrap_or_else(|_| \"http://localhost:8080\".to_string()) + path\n}\n```\n\nSee full example: [openid-examples: warp](https://github.com/kilork/openid-examples/blob/v0.23/examples/warp.rs)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkilork%2Fopenid","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkilork%2Fopenid","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkilork%2Fopenid/lists"}