Skip to content

Authentication#

Perses has various authentication flows configurable. You can choose to authenticate from a native provider that will allow you to create some users, or else rely on an external identity provider.

In both cases - each new user will be saved in the Perses database. - at login time, a Perses session (access_token/refresh_token) will be created

Please note that the number of identity providers is not limited.

authentication:
  providers:
    # Enable or not the native Perses identity provider
    enable_native: true/false
    # Register one or several OIDC provider(s)
    oidc: []
    # Register one or several OAuth provider(s)
    oauth: []

Native provider#

In case a native provider is used, the users and their password are stored in the Perses database.

Login is done through http POST on /api/auth/providers/native/login.

External OIDC/OAuth provider(s)#

It is possible to configure Perses to sign in user with an external identity provider supporting OIDC/Oauth. For both of these provider's types, the flow is quite similar:

When a user sign in with an external provider (e.g. Github) the Perses backend will then use the information collected (email, firstname, lastname, picture) to sync the user in database. Then the backend takes in charge the creation of the access_token/refresh_token that will be used to authenticate this user in the subsequent requests.

The user synchronization can possibly be used to update also its permissions, based on some roles/groups present in the external idp's token.

At the time we write this documentation, there is nothing implemented yet. User have to login first and ask specific permissions to an admin.

=> Configuration example#

authentication:
  providers:
    oidc:
    # Example with an Azure AD OIDC configuration
    - slug_id: azure
      name: "Azure AD"
      client_id: "<secret>"
      client_secret: "<secret>"
      issuer: "https://login.microsoftonline.com/<tenant-id>/v2.0"
      redirect_uri: "http://localhost:3000/api/auth/providers/oidc-azure/callback"
      scopes: ["openid", "profile", "email", "User.read"]
    oauth:
    - slug_id: github
      name: "Github"
      client_id: "<secret>"
      client_secret: "<secret>"
      auth_url: "https://github.com/login/oauth/authorize"
      token_url: "https://github.com/login/oauth/access_token"
      logout_url: "https://github.com/login/oauth/logout"
      redirect_uri: "http://localhost:3000/api/auth/providers/oauth-github/callback"
      user_infos_url: "https://api.github.com/user"

=> Login from external OIDC or OAuth2.0 provider with interactive flow, through WEB UI. (authorization_code)#

sequenceDiagram
    actor hu as John
    #actor ro as Robot
    participant br as Perses Frontend
    participant rp as Perses Backend
    participant op as External Identity Provider

    hu->>br: Login with OIDC provider (e.g Azure AD)
    activate br
    br->>rp: GET /api/auth/providers/{oidc|oauth}/{slug_id}/login
    activate rp
    rp->>br: 302: redirect to Provider
    deactivate rp
    br->>op: /oauth/authorize
    activate op
    op->>br: 302: redirect to Perses
    deactivate op
    br->>rp: GET /api/auth/providers/{oidc|oauth}/{slug_id}/callback?code=...
    activate rp
    alt OIDC
        rp->>op: GET /oauth/token
        activate op
        op->>rp: 200: id_token & access_token
        deactivate op
        rp->>op: GET /api/userinfo<br/> (endpoint from .well-known URL)
        activate op
        op->>rp: 200: User Info
        deactivate op
        Note right of rp: User Info + id token are<br/> used to sync user in database
        rp->>rp: Create or Update user in DB
    else OAUTH 2.0
        rp->>op: GET /oauth/token
        activate op
        op->>rp: 200: access_token
        deactivate op
        rp->>op: GET /api/userinfo<br/> (endpoint from Perses Config)
        activate op
        op->>rp: 200: User Info
        deactivate op
        Note right of rp: Only User Info is<br/> used to sync user in database
        rp->>rp: Create or Update user in DB
    end
    Note right of rp: A new session is created<br /> with a new signed access_token+refresh_token
    rp->>br: 200: save session in cookie
    deactivate rp
    br->>hu: Home Page
    deactivate br
    hu->>br: Click on Projects
    activate br
    br->>rp: GET /api/v1/projects
    activate rp
    rp->>rp: Verify token and permissions
    rp->>br: 200: projects list
    deactivate rp
    br->>hu: Projects Page
    deactivate br

=> Login from external OIDC or OAuth2.0 provider with interactive flow, through percli command line. (device_code)#

sequenceDiagram
    actor hu as John
    #actor ro as Robot
    participant pc as percli Command Line
    participant rp as Perses Backend
    participant op as External Identity Provider

    hu->>pc: EXEC: percli login
    activate pc
    pc->>rp: GET /api/config
    activate rp
    rp->>pc: 200: Config<br/> (containing Providers List)
    deactivate rp
    pc->>hu: PROMPT: which provider?
    deactivate pc
    hu->>pc: select provider
    activate pc
    pc->>rp: GET /api/auth/providers/{oidc|oauth}/{slug_id}/device/code
    activate rp
    rp->>op: GET /oauth/device/code
    activate op
    op->>rp: 200: Device Code + User Code + Verification URL
    deactivate op
    rp->>pc: 200: Device Code + User Code + Verification URL
    pc->>hu: PRINT: User Code + Verification URL (clickable)
    rect rgba(66, 95, 237, 0.2)
        Note over hu, op: Through the browser
        hu->>op: Go to Verification URL + enter User Code
        activate op
        op->>hu: 302: Redirect to Authorization prompt
        hu->>op: Consent
        op->>op: Mark device as authorized
        op->>hu: 200: Invite to close browser
        deactivate op
    end
    Note over hu, op: Meanwhile, percli is polling the following endpoint, until it succeed.
    pc->>rp: GET /api/auth/providers/{oidc|oauth}/{slug_id}/token
    activate rp
    alt OIDC
        rp->>op: GET /oauth/token
        activate op
        op->>rp: 200: id_token & access_token
        deactivate op
        rp->>op: GET /api/userinfo<br/> (endpoint from .well-known URL)
        activate op
        op->>rp: 200: User Info
        deactivate op
        Note right of rp: User Info + id token are<br/> used to sync user in database
        rp->>rp: Create or Update user in DB
    else OAUTH 2.0
        rp->>op: GET /oauth/token
        activate op
        op->>rp: 200: access_token
        deactivate op
        rp->>op: GET /api/userinfo<br/> (endpoint from Perses Config)
        activate op
        op->>rp: 200: User Info
        deactivate op
        Note right of rp: Only User Info is<br/> used to sync user in database
        rp->>rp: Create or Update user in DB
    end
    Note right of rp: A new session is created<br /> with a new signed acces_token+refresh_token
    rp->>pc: 200: access_token + refresh_token
    deactivate rp
    pc->>pc: WRITE: session into config file
    pc->>hu: PRINT: Successfully authenticated!
    deactivate pc
    hu->>pc: EXEC: percli get projects
    activate pc
    pc->>rp: GET /api/v1/projects
    activate rp
    rp->>rp: Verify token and permissions
    rp->>pc: 200: Projects list
    deactivate rp
    pc->>hu: PRINT: Projects list
    deactivate pc

=> Login from external OIDC or OAuth2.0 provider with non-interactive flow. (client_credentials)#

Note: it can be done exactly the same way using directly the backend API. Then one would have to manage the access_token and refresh_token by itself, and send access_token as an Authorization header in the subsequent requests.

sequenceDiagram
    participant ro as Robot
    #actor ro as Robot
    participant pc as percli Command Line
    participant rp as Perses Backend
    participant op as External Identity Provider

    ro->>pc: EXEC: percli login --provider <slug_id> --client-id <client_id> --client-secret <client_secret>
    activate pc
    pc->>rp: GET /api/config
    activate rp
    rp->>pc: 200: Config<br/> (containing Providers List)
    deactivate rp
    pc->>rp: GET /api/auth/providers/{oidc|oauth}/{slug_id}/token
    activate rp
    rp->>op: GET /oauth/token
    activate op
    op->>rp: 200: access_token
    deactivate op
    rp->>op: GET /api/userinfo<br/> (endpoint from Perses Config or .well-known URL)
    activate op
    op->>rp: 200: User Info
    deactivate op
    Note right of rp: Only User Info is<br/> used to sync user in database
    rp->>rp: Create or Update user in DB
    Note right of rp: A new session is created<br /> with a new signed acces_token+refresh_token
    rp->>pc: 200: access_token + refresh_token
    deactivate rp
    pc->>pc: WRITE: session into config file
    pc->>ro: PRINT: Successfully authenticated!
    deactivate pc
    ro->>pc: EXEC: percli get projects
    activate pc
    pc->>rp: GET /api/v1/projects
    activate rp
    rp->>rp: Verify token and permissions
    rp->>pc: 200: Projects list
    deactivate rp
    pc->>ro: PRINT: Projects list
    deactivate pc