PropelAuth
Add authentication and authorization to your application.
This library is meant to be used with a PropelAuth account. You can sign up and get started for free.
Initialize
First, you'll need to initialize the library. You can either call PropelAuth::init
or PropelAuth::fetch_and_init
(which will fetch any unspecified metadata).
let auth = PropelAuth::fetch_and_init(AuthOptions {
auth_url: "REPLACE_ME".to_string(),
api_key: "REPLACE_ME".to_string(),
}).await.expect("Unable to initialize authentication");
Usage / Protecting APIs
Want us to add support for another framework? Reach out at [email protected]
Axum
To use Axum, make sure to enable the axum
feature in your Cargo.toml.
Then, add PropelAuthLayer to your Router:
let auth_layer = PropelAuthLayer::new(auth);
let app = Router::new()
.route("/whoami", get(whoami))
.route("/org/:org_name/whoami", get(org_whoami))
.layer(layer); // <-- here
You can then take User
in as an argument, which will look for an access token in the Authorization header.
// User will automatically return a 401 (Unauthorized) if a valid access token wasn't provided
async fn whoami(user: User) -> String {
user.user_id
}
You can also check which organizations the user is in, and which roles and permissions they have.
// If the user isn't in the provided organization, a 403 is returned
async fn org_whoami(user: User,
Path(org_name): Path<String>) -> Result<String, UnauthorizedOrForbiddenError> {
let org = user.validate_org_membership(RequiredOrg::OrgName(&org_name),
UserRequirementsInOrg::IsRole("Admin"))?;
Ok(format!("You are a {} in {}", org.user_role, org.org_name))
}
You can also get the full auth
struct and make API calls with it:
// Extension(auth) is useful for making API requests
async fn make_req(Extension(auth): Extension<Arc<PropelAuth>>) -> String {
let magic_link = auth.user().create_magic_link(CreateMagicLinkRequest {
email: "[email protected]".to_string(),
..Default::default()
}).await.expect("Couldn't create magic link");
magic_link.url
}
Actix
To use Actix, make sure to enable the actix4
feature in your Cargo.toml.
Add your PropelAuth to your Router:
let auth = PropelAuth::fetch_and_init(/*...*/)
//...
HttpServer::new(move || {
App::new()
.service(whoami)
.service(org_whoami)
.app_data(web::Data::new(auth.clone())) // <-- here
})
You can then take User
in as an argument, which will look for an access token in the Authorization header.
// User will automatically return a 401 (Unauthorized) if a valid access token wasn't provided
#[get("/whoami")]
async fn whoami(user: User) -> impl Responder {
HttpResponse::Ok().json(user)
}
You can also check which organizations the user is in, and which roles and permissions they have.
// If the user isn't in the provided organization, a 403 is returned
#[get("/org/{org_name}/whoami")]
async fn whoami(user: User, org_name: web::Path<String>) -> Result<impl Responder, UnauthorizedOrForbiddenError> {
let org = user.validate_org_membership(RequiredOrg::OrgName(&org_name.into_inner()),
UserRequirementsInOrg::IsRole("Admin"))?;
Ok(HttpResponse::Ok()
.body(format!("You are a {} in {}", org.user_role, org.org_name)))
}
You can also get the full auth
struct and make API calls with it:
#[post("/magic_link")]
async fn make_req(auth: web::Data<PropelAuth>) -> impl Responder {
let magic_link = auth.user().create_magic_link(CreateMagicLinkRequest {
email: "[email protected]".to_string(),
..Default::default()
}).await.expect("Couldn't create magic link");
HttpResponse::Ok().json(magic_link)
}
Other
After initializing auth
, you can verify access tokens by passing in the Authorization header (formatted Bearer TOKEN
):
let result = auth.verify().validate_authorization_header(&authorization_header);
match result {
Ok(user) => { /* valid access token in the header */ }
Err(_) => { /* invalid access token, typically we return a 401 Unauthorized here */ }
}
You can also check which organizations the user is in, and which roles and permissions they have.
let org = auth.validate_org_membership(
&authorization_header,
RequiredOrg::OrgName("acme"),
UserRequirementsInOrg::IsRole("Admin")
)?;
// Alternatively, if you already have a user from validate_authorization_header
let org = user.validate_org_membership(
RequiredOrg::OrgName("acme"),
UserRequirementsInOrg::IsRole("Admin")
)?;
And finally, you can make API calls directly from auth.user()
and auth.org()
Where do the access tokens come from?
They come from your frontend. You can read more about integrating your frontend here.