Casdoor SDK

Introduction

Compared to the standard OIDC protocol, Casdoor provides more functionalities in its SDK, like user management, resource uploading, etc. Connecting to Casdoor via Casdoor SDK costs more time than using a standard OIDC client library but will provide the best flexibility and the most powerful API.

Casdoor SDKs can be divided into two categories:

  1. Frontend SDKs: Javascript SDK for websites, Android or iOS SDKs for Apps. Casdoor supports providing authentication for both websites and mobile Apps.
  2. Backend SDK: SDKs for backend languages like Go, Java, Node.js, Python, PHP, etc.
tip

If your website is developed in a frontend and backend separated manner, then you can use the Javascript SDK: casdoor-js-sdk to integrate Casdoor in frontend. If your web application is a traditional website developed by JSP or PHP, you can just use the backend SDKs only.

Casdoor Frontend SDKDescriptionSource code
Javascript SDKFor websiteshttps://github.com/casdoor/casdoor-js-sdk
Android SDKFor Android appshttps://github.com/casdoor/casdoor-android-sdk
iOS SDKFor iOS appshttps://github.com/casdoor/casdoor-ios-sdk

Next, use one of the following backend SDKs based on the language of your backend:

Casdoor Backend SDKSource code
Go SDKhttps://github.com/casdoor/casdoor-go-sdk
Java SDKhttps://github.com/casdoor/casdoor-java-sdk
Node.js SDKhttps://github.com/casdoor/casdoor-nodejs-sdk
Python SDKhttps://github.com/casdoor/casdoor-python-sdk
PHP SDKhttps://github.com/casdoor/casdoor-php-sdk
.NET SDKhttps://github.com/casdoor/casdoor-dotnet-sdk

For a full list of the official Casdoor SDKs, please see: https://github.com/casdoor?q=sdk&type=all&language=&sort=

How to use Casdoor SDK?

1. Backend SDK configuration

When your application starts up, you need to initialize the Casdoor SDK config by calling the InitConfig() function with required parameters. Take casdoor-go-sdk as example: https://github.com/casbin/casnode/blob/6d4c55f5c9a3c4bd8c85f2493abad3553b9c7ac0/controllers/account.go#L51-L64

  1. var CasdoorEndpoint = "https://door.casbin.com"
  2. var ClientId = "541738959670d221d59d"
  3. var ClientSecret = "66863369a64a5863827cf949bab70ed560ba24bf"
  4. var CasdoorOrganization = "casbin"
  5. var CasdoorApplication = "app-casnode"
  6. //go:embed token_jwt_key.pem
  7. var JwtPublicKey string
  8. func init() {
  9. auth.InitConfig(CasdoorEndpoint, ClientId, ClientSecret, JwtPublicKey, CasdoorOrganization, CasdoorApplication)
  10. }

All the parameters for InitConfig() are explained as follows:

ParameterMustDescription
endpointYesCasdoor Server URL, like https://door.casbin.com or http://localhost:8000
clientIdYesClient ID for the Casdoor application
clientSecretYesClient secret for the Casdoor application
jwtPublicKeyYesThe public key for the Casdoor application’s cert
organizationNameYesThe name for the Casdoor organization
applicationNameNoThe name for the Casdoor application

2. Frontend configuration

First, install casdoor-js-sdk via NPM or Yarn:

  1. npm install casdoor-js-sdk

Or:

  1. yarn add casdoor-js-sdk

Then define the following utility functions (better in a global JS file like Setting.js):

  1. import Sdk from "casdoor-js-sdk";
  2. export function initCasdoorSdk(config) {
  3. CasdoorSdk = new Sdk(config);
  4. }
  5. export function getSignupUrl() {
  6. return CasdoorSdk.getSignupUrl();
  7. }
  8. export function getSigninUrl() {
  9. return CasdoorSdk.getSigninUrl();
  10. }
  11. export function getUserProfileUrl(userName, account) {
  12. return CasdoorSdk.getUserProfileUrl(userName, account);
  13. }
  14. export function getMyProfileUrl(account) {
  15. return CasdoorSdk.getMyProfileUrl(account);
  16. }
  17. export function getMyResourcesUrl(account) {
  18. return CasdoorSdk.getMyProfileUrl(account).replace("/account?", "/resources?");
  19. }
  20. export function signin() {
  21. return CasdoorSdk.signin(ServerUrl);
  22. }

In the entrance file of your frontend code (like index.js or app.js in React), you need to initialize the casdoor-js-sdk by calling the InitConfig() function with required parameters. The first 4 parameters should use the same value as the Casdoor backend SDK. The last parameter redirectPath is relative path for the redirected URL, returned from Casdoor’s login page.

  1. const config = {
  2. serverUrl: "https://door.casbin.com",
  3. clientId: "014ae4bd048734ca2dea",
  4. organizationName: "casbin",
  5. appName: "app-casnode",
  6. redirectPath: "/callback",
  7. };
  8. xxx.initCasdoorSdk(config);

(Optional) Because we are using React as example, so our /callback path is hitting the React route, we use the following React component to receive the /callback call and sends to the backend. You can ignore this step if you are redirecting to backend directly (like in JSP or PHP).

  1. import React from "react";
  2. import { Button, Result, Spin } from "antd";
  3. import { withRouter } from "react-router-dom";
  4. import * as Setting from "./Setting";
  5. class AuthCallback extends React.Component {
  6. constructor(props) {
  7. super(props);
  8. this.state = {
  9. classes: props,
  10. msg: null,
  11. };
  12. }
  13. componentWillMount() {
  14. this.login();
  15. }
  16. login() {
  17. Setting.signin().then((res) => {
  18. if (res.status === "ok") {
  19. Setting.showMessage("success", `Logged in successfully`);
  20. Setting.goToLink("/");
  21. } else {
  22. this.setState({
  23. msg: res.msg,
  24. });
  25. }
  26. });
  27. }
  28. render() {
  29. return (
  30. <div style={{ textAlign: "center" }}>
  31. {this.state.msg === null ? (
  32. <Spin
  33. size="large"
  34. tip="Signing in..."
  35. style={{ paddingTop: "10%" }}
  36. />
  37. ) : (
  38. <div style={{ display: "inline" }}>
  39. <Result
  40. status="error"
  41. title="Login Error"
  42. subTitle={this.state.msg}
  43. extra={[
  44. <Button type="primary" key="details">
  45. Details
  46. </Button>,
  47. <Button key="help">Help</Button>,
  48. ]}
  49. />
  50. </div>
  51. )}
  52. </div>
  53. );
  54. }
  55. }
  56. export default withRouter(AuthCallback);

3. Get login URLs

Next you can show the “Sign up” and “Sign in” buttons or links to your users. The URLs can either be retrieved in the frontend or backend. See more details at: /docs/basic/core-concepts#login-urls

4. Get and verify access token

Here are the steps:

  1. The user clicks the login URL and is redirected to Casdoor’s login page, like: https://door.casbin.com/login/oauth/authorize?client_id=014ae4bd048734ca2dea&response_type=code&redirect_uri=https%3A%2F%2Fforum.casbin.com%2Fcallback&scope=read&state=app-casnode
  2. The user enters username & password and clicks Sign In (or just click the third-party login button like Sign in with GitHub).
  3. The user is redirected back to your application with the authorization code issued by Casdoor (like: https://forum.casbin.com?code=xxx&state=yyy), your application’s backend needs to exchange the authorization code with the access token and verify that the access token is valid and issued by Casdoor. The functions GetOAuthToken() and ParseJwtToken() are provided by Casdoor backend SDK.

The following code shows how to get and verify the access token. For a real example of Casnode (a forum website written in Go), see: https://github.com/casbin/casnode/blob/6d4c55f5c9a3c4bd8c85f2493abad3553b9c7ac0/controllers/account.go#L51-L64

  1. // get code and state from the GET parameters of the redirected URL
  2. code := c.Input().Get("code")
  3. state := c.Input().Get("state")
  4. // exchange the access token with code and state
  5. token, err := auth.GetOAuthToken(code, state)
  6. if err != nil {
  7. panic(err)
  8. }
  9. // verify the access token
  10. claims, err := auth.ParseJwtToken(token.AccessToken)
  11. if err != nil {
  12. panic(err)
  13. }

If ParseJwtToken() finishes with no error, then the user has successfully logged into the application. The returned claims can be used to identity the user later.

4. Identify user with access token

info

This part is actually your application’s own business logic and not part of OIDC, OAuth or Casdoor. We just provide good practices as a lot of people don’t know what to do for next step.

In Casdoor, access token is usually identical as ID token. They are the same thing. So the access token contains all information for the logged-in user.

The variable claims returned by ParseJwtToken() is defined as:

  1. type Claims struct {
  2. User
  3. AccessToken string `json:"accessToken"`
  4. jwt.RegisteredClaims
  5. }
  1. User: the User object, containing all information for the logged-in user, see definition at: /docs/basic/core-concepts#user
  2. AccessToken: the access token string.
  3. jwt.RegisteredClaims: some other values required by JWT.

At this moment, the application usually has two ways to remember the user session: session and JWT.

Session

The Method to set session varies greatly depending on the language and web framework. E.g., Casnode uses Beego web framework and set session by calling: c.SetSessionUser().

  1. token, err := auth.GetOAuthToken(code, state)
  2. if err != nil {
  3. panic(err)
  4. }
  5. claims, err := auth.ParseJwtToken(token.AccessToken)
  6. if err != nil {
  7. panic(err)
  8. }
  9. claims.AccessToken = token.AccessToken
  10. c.SetSessionUser(claims) // set session

JWT

The accessToken returned by Casdoor is actually a JWT. So if your application uses JWT to keep user session, just use the access token directly for it:

  1. Send the access token to frontend, save it in places like localStorage of the browser.
  2. Let the browser sends the access token to backend for every request.
  3. Call ParseJwtToken() or your own function to verify the access token and get logged-in user information in your backend.

5. (Optional) Interact with the User table

info

This part is provided by Casdoor Public API and not part of the OIDC or OAuth.

Casdoor Backend SDK provides a lot of helper functions, not limited to:

  • GetUser(name string): get a user by username.
  • GetUsers(): get all users.
  • AddUser(): add a user.
  • UpdateUser(): update a user.
  • DeleteUser(): delete a user.
  • CheckUserPassword(auth.User): check user’s password.

These functions are implemented by making RESTful calls against Casdoor Public API. If a function is not provided in Casdoor Backend SDK, you can make RESTful calls by yourself.