I can not help with that specific authentication provider (never worked with office 365) but this is general steps that you need to follow:
- Send request(s) to get access and refresh tokens
 
- Store tokens in a storage that persist data through reloads/restarts (for web it would be localStorage, for RN sqlite or asyncstorage or whatever do you use)
 
- Save token and authentication state that it's available for all your components (Redux, Context API or even your own solution). This is needed to show/hide parts of application when user authenticates, unauthenticates or token is expired
 
- You need to know somehow when token will be expired (can't say how to do it but API docs should have some info) and use 
setTimeout in order to refresh 
- When you refreshed token, you should persist it (see n.2) and update global auth state (see n.3)
 
- When app just (re)started, check if you have access/refresh tokens persisted in storage (see n.2) and update global auth state accordingly (see n.3)
 
- You routes should react to auth state changes (see docs to your routing library, something about protected/authenticated routes). Your components that display sensitive content also should react to auth state changes.
 
Here is my auth solution for Reactjs (do not have RN example, unfortunately) that authenticates client against my own API using JWT. Access token in this scenario is refresh token as well. I use an approach without Redux, just pure React and JS. I hope this would help you.
import { useCallback, useState, useEffect } from "react";
import JWT from "jsonwebtoken";
import { ENV } from "../config";
import { useLanguageHeaders } from "./i18n";
const decodeToken = (token) =>
  typeof token === "string" ? JWT.decode(token) : null;
//This class is responsible for authentication, 
//refresh and global auth state parts
//I create only one instance of AuthProvider and export it, 
//so it's kind of singleton
class AuthProvider {
  //Getter for _authStatus
  get authStatus() {
    return this._authStatus;
  }
  constructor({ tokenEndpoint, refreshEndpoint, refreshLeeway = 60 }) {
    this._tokenEndpoint = tokenEndpoint;
    this._refreshEndpoint = refreshEndpoint;
    this._refreshLeeway = refreshLeeway;
    //When app is loaded, I load token from local storage
    this._loadToken();
    //And start refresh function that checks expiration time each second
    //and updates token if it will be expired in refreshLeeway seconds
    this._maybeRefresh();
  }
  //This method is called in login form
  async authenticate(formData, headers = {}) {
    //Making a request to my API
    const response = await fetch(this._tokenEndpoint, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        ...headers,
      },
      redirect: "follow",
      body: JSON.stringify(formData),
    });
    const body = await response.json();
    if (response.status === 200) {
      //Authentication successful, persist token and update _authStatus
      this._updateToken(body.token);
    } else {
      //Error happened, replace stored token (if any) with null 
      //and update _authStatus
      this._updateToken(null);
      throw new Error(body);
    }
  }
  //This method signs user out by replacing token with null
  unauthenticate() {
    this._updateToken(null);
  }
  //This is needed so components and routes are able to 
  //react to changes in _authStatus
  addStatusListener(listener) {
    this._statusListeners.push(listener);
  }
  //Components need to unsubscribe from changes when they unmount
  removeStatusListener(listener) {
    this._statusListeners = this._statusListeners.filter(
      (cb) => cb !== listener
    );
  }
  _storageKey = "jwt";
  _refreshLeeway = 60;
  _tokenEndpoint = "";
  _refreshEndpoint = "";
  _refreshTimer = undefined;
  //This field holds authentication status
  _authStatus = {
    isAuthenticated: null,
    userId: null,
  };
  _statusListeners = [];
  //This method checks if token refresh is needed, performs refresh 
  //and calls itself again in a second
  async _maybeRefresh() {
    clearTimeout(this._refreshTimer);
    try {
      const decodedToken = decodeToken(this._token);
      if (decodedToken === null) {
        //no token - no need to refresh
        return;
      }
      //Note that in case of JWT expiration date is built-in in token
      //itself, so I do not need to make requests to check expiration
      //Otherwise you might want to store expiration date in _authStatus
      //and localStorage
      if (
        decodedToken.exp * 1000 - new Date().valueOf() >
        this._refreshLeeway * 1000
      ) {
        //Refresh is not needed yet because token will not expire soon
        return;
      }
      if (decodedToken.exp * 1000 <= new Date().valueOf()) {
        //Somehow we have a token that is already expired
        //Possible when user loads app after long absence
        this._updateToken(null);
        throw new Error("Token is expired");
      }
      //If we are not returned from try block earlier, it means 
      //we need to refresh token
      //In my scenario access token itself is used to get new one
      const response = await fetch(this._refreshEndpoint, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        redirect: "follow",
        body: JSON.stringify({ token: this._token }),
      });
      const body = await response.json();
      if (response.status === 401) {
        //Current token is bad, replace it with null and update _authStatus
        this._updateToken(null);
        throw new Error(body);
      } else if (response.status === 200) {
        //Got new token, replace existing one
        this._updateToken(body.token);
      } else {
        //Network error, maybe? I don't care unless its 401 status code
        throw new Error(body);
      }
    } catch (e) {
      console.log("Something is wrong when trying to refresh token", e);
    } finally {
      //Finally block is executed even if try block has return statements
      //That's why I use it to schedule next refresh try
      this._refreshTimer = setTimeout(this._maybeRefresh.bind(this), 1000);
    }
  }
  //This method persist token and updates _authStatus
  _updateToken(token) {
    this._token = token;
    this._saveCurrentToken();
    try {
      const decodedToken = decodeToken(this._token);
      if (decodedToken === null) {
        //No token
        this._authStatus = {
          ...this._authStatus,
          isAuthenticated: false,
          userId: null,
        };
      } else if (decodedToken.exp * 1000 <= new Date().valueOf()) {
        //Token is expired
        this._authStatus = {
          ...this._authStatus,
          isAuthenticated: false,
          userId: null,
        };
      } else {
        //Token is fine
        this._authStatus = {
          ...this._authStatus,
          isAuthenticated: true,
          userId: decodedToken.id,
        };
      }
    } catch (e) {
      //Token is so bad that can not be decoded (malformed)
      this._token = null;
      this._saveCurrentToken();
      this._authStatus = {
        ...this._authStatus,
        isAuthenticated: false,
        userId: null,
      };
      throw e;
    } finally {
      //Notify subscribers that _authStatus is updated
      this._statusListeners.forEach((listener) => listener(this._authStatus));
    }
  }
  //Load previously persisted token (called in constructor)
  _loadToken() {
    this._updateToken(window.localStorage.getItem(this._storageKey));
  }
  //Persist token
  _saveCurrentToken() {
    if (typeof this._token === "string") {
      window.localStorage.setItem(this._storageKey, this._token);
    } else {
      window.localStorage.removeItem(this._storageKey);
    }
  }
}
//Create authProvider instance
const authProvider = new AuthProvider(ENV.auth);
//This hook gives a component a function to authenticate user
export const useAuthenticate = () => {
  const headers = useLanguageHeaders();
  return useCallback(
    async (formData) => {
      await authProvider.authenticate(formData, headers);
    },
    [headers]
  );
};
//This hook gives a function to unauthenticate
export const useUnauthenticate = () => {
  return useCallback(() => authProvider.unauthenticate(), []);
};
//This hook allows components to get authentication status 
//and react to changes
export const useAuthStatus = () => {
  const [authStatus, setAuthStatus] = useState(authProvider.authStatus);
  useEffect(() => {
    authProvider.addStatusListener(setAuthStatus);
    return () => {
      authProvider.removeStatusListener(setAuthStatus);
    };
  }, []);
  return authStatus;
};
This line of code inside of functional component allows to know if user is authenticated or not: const { isAuthenticated } = useAuthStatus();