To self-host with a custom auth provider, you will need to do the following steps.
You can do so by extending the AbstractAuthProvider
class and implementing the following functions:
authenticate
: This function is called when the user goes into /admin
and they are not logged in (determined by getUser
). This function should redirect the user to the login page or do whatever is necessary to authenticate the user.
getUser
: This function is called when the user goes into /admin
and is used to determine if the user is logged in. If it returns a truthy value, the user is logged in. If it returns a falsy value the user is not logged in.
getToken
: This function is called when a request is made to the GraphQL endpoint. It should return an object with an id_token
property. This will be passed as an Authorization
header in the format Bearer <id_token>
logOut
: This function is called when the user clicks the logout button.
authorize
: This function is called when the user goes into /admin
and is logged in. It is used to determine if the user is authorized to access the admin. If it returns a truthy value, the user is authorized. If it returns a falsy value the user is not authorized.
getSessionProvider
: Return a React context provider that wraps the TinaCMS UI.
import { AbstractAuthProvider } from 'tinacms'export class CustomAuthProvider extends AbstractAuthProvider {constructor() {super()// Do any setup here}async authenticate(props?: {}): Promise<any> {// Do any authentication here}async getToken() {// Return the token here. The token will be passed as an Authorization header in the format `Bearer <token>`}async getUser() {// Returns a truthy value, the user is logged in and if it returns a falsy value the user is not logged in.}async logout() {// Do any logout logic here}async authorize(context?: any): Promise<any> {// Do any authorization logic here}getSessionProvider() {// GetSessionProvider can be deleted if not needed// OPTIONALLY Return a React context provider to that will wrap the admin}}
Now you can add your custom auth provider to your config file:
export default defineConfig({authProvider: isLocal ? new LocalAuthProvider() : new CustomAuthProvider(),//...})
TinaNodeBackend
takes an authProvider
Prop.
export interface BackendAuthProvider {initialize?: () => Promise<void>isAuthorized: (req: IncomingMessage,res: ServerResponse) => Promise<| {isAuthorized: true}| {isAuthorized: falseerrorMessage: stringerrorCode: number}>// You can use this if you need to attach any extra routes to the backend. Ex, a callback route for OAuthextraRoutes?: {[key: string]: {// If secure is true the `isAuthorized` function will be called before the handler is calledsecure?: booleanhandler: (req: IncomingMessage, res: ServerResponse) => Promise<void>}}}
This interface must be passed to the authProvider
prop of TinaNodeBackend
. You can get the token from the request by calling req.headers.authorization
. This token should be validated in the isAuthorized
function.
const CustomBackendAuth = () => {return {isAuthorized: async (req, res) => {const token = req.headers.authorization// Validate the token herereturn {isAuthorized: true,}},}}
For an example of how to do this, see the Auth.js Backend.
Once you have created an object that implements the BackendAuthProvider
interface, you can pass it to the authProvider
prop of TinaNodeBackend
.
/pages/api/tina/[...routes].{ts,js}
const handler = TinaNodeBackend({authProvider: isLocal ? LocalBackendAuthProvider() : CustomBackendAuth(),databaseClient,})
© TinaCMS 2019–2024