title | author | image | tags | redirect_to | ||
---|---|---|---|---|---|---|
Authentication to sensenet with IdentityServer4 |
|
../img/posts/lock-is.jpg |
|
We have changed the authentication mechanism for sensenet 7 to use IdentityServer4. Here are the things you need to know when you use it in a single page application.
IdentityServer4 is an OpenID Connect and OAuth 2.0 framework for ASP.NET Core 3.0. Come again? What does that even mean? What is OpenID Connect and OAuth 2.0?
Quoting from https://oauth.net/2/
OAuth 2.0 is the industry-standard protocol for authorization. OAuth 2.0 focuses on client developer simplicity while providing specific authorization flows for web applications, desktop applications, mobile phones, and living room devices. This specification and its extensions are being developed within the IETF OAuth Working Group.
Quoting from https://openid.net/connect/
OpenID Connect 1.0 is a simple identity layer on top of the OAuth 2.0 protocol. It allows Clients to verify the identity of the End-User based on the authentication performed by an Authorization Server, as well as to obtain basic profile information about the End-User in an interoperable and REST-like manner.
Ok, so IdentityServer4 is implementing the industry-standard protocol for authorization. That sounds awesome. We don't have to implement hacky/non-standard ways to implement authorization, IdentityServer4 does most of the work for us.
The easiest way is to use our newly created React component library for handling authentication through a provider (@sensenet/authentication-oidc-react). It uses oidc-client under the hood. If you are using another framework or just vanilla js, this lib is your best bet.
- Add @sensenet/authentication-oidc-react to your react app either with
yarn add @sensenet/authentication-oidc-react
or withnpm install @sensenet/authentication-oidc-react
- Add a configuration file like this:
import { UserManagerSettings } from '@sensenet/authentication-oidc-react'
export const repositoryUrl = 'https://my-service.sensenet.com/' // This is the repository you want to log in to
export const configuration: UserManagerSettings = {
automaticSilentRenew: true, // Access tokens only valid for a period of time with this set to true it will be renewed 1 minute before expiration
client_id: '', //clientId of your repository
redirect_uri: `${window.location.origin}/authentication/callback`, // This is the url it will return with the access token
response_type: 'code', // This value tells OAuth2 what should be in the response, we want the access token
post_logout_redirect_uri: `${window.location.origin}/`, // This is the url the server will redirect after logout
scope: 'openid profile sensenet', // The scopes we want access to, don't forget to add sensenet!
authority: 'https://is.test.sensenet.com/', // The identity server that will talk with our repository
silent_redirect_uri: `${window.location.origin}/authentication/silent_callback`, // This url is going to be called for silent login
extraQueryParams: { snrepo: repositoryUrl }, // This is an important bit, we need to set snrepo to our repositoryUrl so IdentityServer will know who should it talk to for authorization
}
- Wrap your app with a provider like this
import { AuthenticationProvider, useOidcAuthentication, UserManagerSettings } from '@sensenet/authentication-oidc-react'
import { Repository } from '@sensenet/client-core'
import { RepositoryContext } from '@sensenet/hooks-react'
import React, { PropsWithChildren } from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter, useHistory } from 'react-router-dom'
ReactDOM.render(
<AppProviders>
<App />
</AppProviders>,
document.getElementById('root'),
)
export function AppProviders({ children }: PropsWithChildren<{}>) {
return (
<BrowserRouter>
<AuthProvider>
<RepositoryProvider>{children}</RepositoryProvider>
</AuthProvider>
</BrowserRouter>
)
}
export const AuthProvider = ({ children }: PropsWithChildren<{}>) => {
const history = useHistory()
return (
<AuthenticationProvider configuration={configuration} history={history}>
{children}
</AuthenticationProvider>
)
}
export const RepositoryProvider = ({ children }: PropsWithChildren<{}>) => {
const { oidcUser } = useOidcAuthentication()
if (!oidcUser) {
return <LoginForm />
}
return (
<RepositoryContext.Provider value={new Repository({ repositoryUrl, token: oidcUser.access_token })}>
{children}
</RepositoryContext.Provider>
)
}
- That is it! 🎉 You can now authenticate with your user.
You can get the authority and client_id config from the service with this action https://my-service.sensenet.com/odata.svc/('Root')/GetClientRequestParameters?clientType=adminui
Photo by Maxim Zhgulev on Unsplash